Fixed some identity-constraint issues: Restructured IDC node-tables

* xmlschemas.c: Fixed some identity-constraint issues:
  Restructured IDC node-tables
  Allowed IDCs to resolve also to nodes of complex type with
  simple content.
  Added check for keyrefs with references to keyrefs.
  IDC target-nodes were interferring with IDC node-tables,
  since they used one list of entries only. I separated this
  one big list into 3 lists: 1 for IDC node-table entries,
  1 for _duplicates_ of IDC node-table entries and 1 for
  IDC target-nodes. More code, but cleaner and it works at last.
  Keyrefs will fail to resolve to duplicate key/unique entries.
  I thought this was already working this way, but it didn't.
  The wording of the definition for [node table] in the spec
  can lead to a scenario, where keyrefs resolve perfectly, even
  if the relevant key-sequences of the referenced key/unique have
  duplicates in the subtree. Currently only Saxon 8.5.1 is
  dissallowing resolution to duplicate entries correctly - we
  will follow Saxon here.
  Removed some intel compiler warnings (reported by
  Kjartan Maraas, bug #318517).
* pattern.c: Fixed an IDC-XPath problem when resolving to
  attributes.
diff --git a/xmlschemas.c b/xmlschemas.c
index 1dcd87f..43e66fb 100644
--- a/xmlschemas.c
+++ b/xmlschemas.c
@@ -17,6 +17,10 @@
  *     against their types.
  *   - Eliminate item creation for: ??
  *
+ * URGENT TODO:
+ *   - For xsi-driven schema acquisition, augment the IDCs after every
+ *     acquisition episode (xmlSchemaAugmentIDC).
+ *
  * NOTES:
  *   - Elimated item creation for: <restriction>, <extension>,
  *     <simpleContent>, <complexContent>, <list>, <union>
@@ -78,7 +82,15 @@
 
 #define DEBUG_ATTR_VALIDATION 0
 
-/* #define DEBUG_IDC 1 */
+/* #define DEBUG_IDC */
+
+/* #define DEBUG_IDC_NODE_TABLE */
+
+#ifdef DEBUG_IDC
+ #ifndef DEBUG_IDC_NODE_TABLE
+  #define DEBUG_IDC_NODE_TABLE
+ #endif
+#endif   
 
 /* #define ENABLE_PARTICLE_RESTRICTION 1 */
 
@@ -86,6 +98,8 @@
 
 /* #define ENABLE_NAMED_LOCALS */
 
+#define ENABLE_IDC_NODE_TABLES
+
 #define DUMP_CONTENT_MODEL
 
 #ifdef LIBXML_READER_ENABLED
@@ -285,6 +299,10 @@
 #define WXS_ADD_PENDING(ctx, item) \
     xmlSchemaAddItemSize(&((ctx)->constructor->pending), 10, item)
 /*
+* xmlSchemaItemList macros.
+*/
+#define WXS_ILIST_IS_EMPTY(l) ((l == NULL) || ((l)->nbItems == 0))
+/*
 * Misc macros.
 */
 #define IS_SCHEMA(node, type) \
@@ -292,7 +310,7 @@
     (xmlStrEqual(node->name, (const xmlChar *) type)) && \
     (xmlStrEqual(node->ns->href, xmlSchemaNs)))
 
-#define FREE_AND_NULL(str) if (str != NULL) { xmlFree((xmlChar *) str); str = NULL; }
+#define FREE_AND_NULL(str) if ((str) != NULL) { xmlFree((xmlChar *) (str)); str = NULL; }
 
 /*
 * Since we put the default/fixed values into the dict, we can
@@ -730,7 +748,7 @@
 struct _xmlSchemaIDCAug {
     xmlSchemaIDCAugPtr next; /* next in a list */
     xmlSchemaIDCPtr def; /* the IDC definition */
-    int bubbleDepth; /* the lowest tree level to which IDC
+    int keyrefDepth; /* the lowest tree level to which IDC
                         tables need to be bubbled upwards */
 };
 
@@ -774,11 +792,10 @@
     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 */
+    xmlSchemaItemListPtr dupls;
 };
 
+
 #define XPATH_STATE_OBJ_TYPE_IDC_SELECTOR 1
 #define XPATH_STATE_OBJ_TYPE_IDC_FIELD 2
 
@@ -813,17 +830,20 @@
 /**
  * xmlSchemaIDCMatcher:
  *
- * Used to  IDC selectors (and fields) successively.
+ * Used to evaluate IDC selectors (and fields).
  */
 struct _xmlSchemaIDCMatcher {
     int type;
     int depth; /* the tree depth at creation time */
     xmlSchemaIDCMatcherPtr next; /* next in the list */
     xmlSchemaIDCAugPtr aidc; /* the augmented IDC item */
+    int idcType;
     xmlSchemaPSVIIDCKeyPtr **keySeqs; /* the key-sequences of the target
                                          elements */
     int sizeKeySeqs;
     int targetDepth;
+    xmlSchemaItemListPtr targets; /* list of target-node
+                                     (xmlSchemaPSVIIDCNodePtr) entries */
 };
 
 /*
@@ -873,7 +893,9 @@
 
     const xmlChar **nsBindings; /* Namespace bindings on this element */
     int nbNsBindings;
-    int sizeNsBindings;
+    int sizeNsBindings;    
+
+    int hasKeyrefs;
 };
 
 #define XML_SCHEMAS_ATTR_UNKNOWN 1
@@ -943,7 +965,7 @@
     xmlCharEncoding enc;
     xmlSAXHandlerPtr sax;
     xmlParserCtxtPtr parserCtxt;
-    void *user_data;
+    void *user_data; /* TODO: What is this for? */
 
     int err;
     int nberrors;
@@ -993,6 +1015,9 @@
 
     int skipDepth;
     xmlSchemaItemListPtr nodeQNames;
+    int hasKeyrefs;
+    int createIDCNodeTables;
+    int psviExposeIDCNodeTables;
 };
 
 /**
@@ -4422,7 +4447,7 @@
                     (xmlHashScannerFull) xmlSchemaElementDump, output);
 }
 
-#ifdef DEBUG_IDC
+#ifdef DEBUG_IDC_NODE_TABLE
 /**
  * xmlSchemaDebugDumpIDCTable:
  * @vctxt: the WXS validation context
@@ -4435,7 +4460,8 @@
 			   const xmlChar *localName,
 			   xmlSchemaPSVIIDCBindingPtr bind)
 {
-    xmlChar *str = NULL, *value;
+    xmlChar *str = NULL;
+    const xmlChar *value;
     xmlSchemaPSVIIDCNodePtr tab;
     xmlSchemaPSVIIDCKeyPtr key;
     int i, j, res;
@@ -4448,8 +4474,8 @@
 	return;
     do {
 	fprintf(output, "IDC:   BINDING %s\n",
-	    xmlSchemaFormatQName(&str, bind->definition->targetNamespace,
-	    bind->definition->name));
+	    xmlSchemaGetComponentQName(&str, 
+		bind->definition));
 	FREE_AND_NULL(str)
 	for (i = 0; i < bind->nbNodes; i++) {
 	    tab = bind->nodeTable[i];
@@ -4471,6 +4497,29 @@
 	    }
 	    fprintf(output, ")\n");
 	}
+	if (bind->dupls && bind->dupls->nbItems) {
+	    fprintf(output, "IDC:     dupls:\n");
+	    for (i = 0; i < bind->dupls->nbItems; i++) {
+		tab = bind->dupls->items[i];
+		fprintf(output, "         ( ");
+		for (j = 0; j < bind->definition->nbFields; j++) {
+		    key = tab->keys[j];
+		    if ((key != NULL) && (key->val != NULL)) {
+			res = xmlSchemaGetCanonValue(key->val, &value);
+			if (res >= 0)
+			    fprintf(output, "\"%s\" ", value);
+			else
+			    fprintf(output, "CANON-VALUE-FAILED ");
+			if (res == 0)
+			    FREE_AND_NULL(value)
+		    } else if (key != NULL)
+		    fprintf(output, "(no val), ");
+			else
+			    fprintf(output, "(key missing), ");
+		}
+		fprintf(output, ")\n");
+	    }
+	}
 	bind = bind->next;
     } while (bind != NULL);
 }
@@ -10671,7 +10720,7 @@
 	}
     }
     /*
-    * Locate and aquire the schema document.
+    * Locate and acquire the schema document.
     */
     if (schemaLocation != NULL)
 	schemaLocation = xmlSchemaBuildAbsoluteURI(pctxt->dict,
@@ -10809,7 +10858,7 @@
 {
     xmlNodePtr child = NULL;
     const xmlChar *schemaLocation = NULL;
-    int res = 0, /* docRes = 0, located = 0, */ hasRedefinitions = 0;
+    int res = 0; /* hasRedefinitions = 0 */
     int isChameleon = 0, wasChameleon = 0;
     xmlSchemaBucketPtr bucket = NULL;
 
@@ -10968,13 +11017,13 @@
 		xmlSchemaParseSimpleType(pctxt, schema, child, 1);
 	    } else if (IS_SCHEMA(child, "complexType")) {
 		xmlSchemaParseComplexType(pctxt, schema, child, 1);
-		hasRedefinitions = 1;
+		/* hasRedefinitions = 1; */
 	    } else if (IS_SCHEMA(child, "group")) {		
-		hasRedefinitions = 1;		
+		/* hasRedefinitions = 1; */
 		xmlSchemaParseModelGroupDefinition(pctxt,
 		    schema, child);
 	    } else if (IS_SCHEMA(child, "attributeGroup")) {
-		hasRedefinitions = 1;
+		/* hasRedefinitions = 1; */
 		xmlSchemaParseAttributeGroupDefinition(pctxt, schema,
 		    child);
 	    }
@@ -12920,8 +12969,6 @@
 xmlSchemaBuildContentModel(xmlSchemaTypePtr type,
 			   xmlSchemaParserCtxtPtr ctxt)
 {
-    xmlAutomataStatePtr start;
-
     if ((type->type != XML_SCHEMA_TYPE_COMPLEX) ||
 	(type->contModel != NULL) ||
 	((type->contentType != XML_SCHEMA_CONTENT_ELEMENTS) &&
@@ -12939,7 +12986,7 @@
 	    "Cannot create automata for complex type %s\n", type->name);
         return;
     }
-    start = ctxt->state = xmlAutomataGetInitState(ctxt->am);
+    ctxt->state = xmlAutomataGetInitState(ctxt->am);
     /*
     * Build the automaton.
     */
@@ -13898,7 +13945,7 @@
 				       xmlSchemaWildcardPtr baseWild)
 {        
     xmlSchemaAttributeUsePtr cur = NULL, bcur;
-    int i, j, found, err = 0;
+    int i, j, found; /* err = 0; */
     const xmlChar *bEffValue;
     int effFixed;
     
@@ -13942,7 +13989,7 @@
 			    xmlSchemaGetComponentDesignation(&str, baseItem),
 			    NULL, NULL);
 			FREE_AND_NULL(str);
-			err = pctxt->err;
+			/* err = pctxt->err; */
 		    } else if (xmlSchemaCheckCOSSTDerivedOK(pctxt,
 			WXS_ATTRUSE_TYPEDEF(cur),
 			WXS_ATTRUSE_TYPEDEF(bcur), 0) != 0)
@@ -13972,7 +14019,7 @@
 			FREE_AND_NULL(strA);
 			FREE_AND_NULL(strB);
 			FREE_AND_NULL(strC);
-			err = pctxt->err;
+			/* err = pctxt->err; */
 		    } else {
 			/*
 			* 2.1.3 [Definition:]  Let the effective value
@@ -14017,7 +14064,7 @@
 					baseItem),
 				    NULL, NULL);
 				FREE_AND_NULL(str);
-				err = pctxt->err;
+				/* err = pctxt->err; */
 			    }
 			}
 		    }
@@ -14048,7 +14095,7 @@
 			xmlSchemaGetComponentDesignation(&str, baseItem),
 			NULL, NULL);
 		    FREE_AND_NULL(str);
-		    err = pctxt->err;
+		    /* err = pctxt->err; */
 		}
 	    }
 	}
@@ -16999,7 +17046,7 @@
 	bfmaxlen = NULL, bfminlen = NULL, /* facets of the base type */
 	bfmininc = NULL, bfmaxinc = NULL,
 	bfminexc = NULL, bfmaxexc = NULL;
-    int res, err = 0, fixedErr;
+    int res; /* err = 0, fixedErr; */
 
     /*
     * SPEC st-restrict-facets 1:
@@ -17083,7 +17130,6 @@
 		break;
 	}
     }
-    err = 0;
     /*
     * length and minLength or maxLength (2.2) + (3.2)
     */
@@ -17465,8 +17511,8 @@
 	* Search for a duplicate facet in the current type.
 	*/
 	link = type->facetSet;
-	err = 0;
-	fixedErr = 0;
+	/* err = 0; */
+	/* fixedErr = 0; */
 	while (link != NULL) {
 	    facet = link->facet;
 	    if (facet->type == bfacet->type) {
@@ -19985,13 +20031,15 @@
  * @name:  the attribute name
  *
  * Resolve keyRef references to key/unique IDCs.
+ * Schema Component Constraint:
+ *   Identity-constraint Definition Properties Correct (c-props-correct)
  */
-static void
+static int
 xmlSchemaResolveIDCKeyReferences(xmlSchemaIDCPtr idc,
 			  xmlSchemaParserCtxtPtr pctxt)
 {
     if (idc->type != XML_SCHEMA_TYPE_IDC_KEYREF)
-        return;
+        return(0);
     if (idc->ref->name != NULL) {
 	idc->ref->item = (xmlSchemaBasicItemPtr)
 	    xmlSchemaGetIDC(pctxt->schema, idc->ref->name,
@@ -20007,7 +20055,18 @@
 		"refer", idc->ref->name,
 		idc->ref->targetNamespace,
 		XML_SCHEMA_TYPE_IDC_KEY, NULL);
-            return;
+            return(pctxt->err);
+	} else if (idc->ref->item->type == XML_SCHEMA_TYPE_IDC_KEYREF) {
+	    /*
+	    * SPEC c-props-correct (1)
+	    */
+	    xmlSchemaCustomErr(ACTXT_CAST pctxt,
+		XML_SCHEMAP_C_PROPS_CORRECT,
+		NULL, WXS_BASIC_CAST idc,
+		"The keyref references a keyref",
+		NULL, NULL);
+	    idc->ref->item = NULL;
+	    return(pctxt->err);
 	} else {
 	    if (idc->nbFields !=
 		((xmlSchemaIDCPtr) idc->ref->item)->nbFields) {
@@ -20021,18 +20080,20 @@
 		* the cardinality of the {fields} must equal that of
 		* the {fields} of the {referenced key}.
 		*/
-		xmlSchemaPCustomErr(pctxt,
+		xmlSchemaCustomErr(ACTXT_CAST pctxt,
 		    XML_SCHEMAP_C_PROPS_CORRECT,
-		    WXS_BASIC_CAST idc, NULL,
+		    NULL, WXS_BASIC_CAST idc,
 		    "The cardinality of the keyref differs from the "
-		    "cardinality of the referenced key '%s'",
+		    "cardinality of the referenced key/unique '%s'",
 		    xmlSchemaFormatQName(&str, refer->targetNamespace,
-			refer->name) 
-		);
+			refer->name),
+		    NULL);
 		FREE_AND_NULL(str)
+		return(pctxt->err);
 	    }
 	}
     }
+    return(0);
 }
 
 static int
@@ -20077,6 +20138,15 @@
 	/*
 	* First try to locate the redefined component in the
 	* schema graph starting with the redefined schema.
+	* NOTE: According to this schema bug entry:
+	*   http://lists.w3.org/Archives/Public/www-xml-schema-comments/2005OctDec/0019.html
+	*   it's not clear if the referenced component needs to originate
+	*   from the <redefine>d schema _document_ or the schema; the latter
+	*   would include all imported and included sub-schemas of the
+	*   <redefine>d schema. Currenlty we latter approach is used.
+	*   SUPPLEMENT: It seems that the WG moves towards the latter
+	*   approach, so we are doing it right.
+	*   
 	*/
 	prev = xmlSchemaFindRedefCompInGraph(
 	    redef->targetBucket, item->type,
@@ -20323,6 +20393,13 @@
     * Add global components to the schema's hash tables.
     * This is the place where duplicate components will be
     * detected.
+    * TODO: I think normally we should support imports of the
+    *   same namespace from multiple locations. We don't do currently,
+    *   but if we do then according to:
+    *   http://www.w3.org/Bugs/Public/show_bug.cgi?id=2224
+    *   we would need, if imported directly, to import redefined
+    *   components as well to be able to catch clashing components.
+    *   (I hope I'll still know what this means after some months :-()
     */
     if (bucket == NULL)
 	return(-1);
@@ -21164,7 +21241,7 @@
 	return(ret);
     if (bucket == NULL) {
 	PERROR_INT("xmlSchemaAssembleByLocation",
-	    "no schema bucket aquired");
+	    "no schema bucket acquired");
 	return(-1);
     } 
     /*
@@ -21259,8 +21336,9 @@
     * Parse the value; we will assume an even number of values
     * to be given (this is how Xerces and XSV work).
     *
-    * URGENT TODO: !! This needs to work also for multiple
-    * schemaLocation attributes !!
+    * URGENT TODO: !! This needs to work for both
+    * @noNamespaceSchemaLocation AND @schemaLocation on the same
+    * element !!
     */
     iattr = xmlSchemaGetMetaAttrInfo(vctxt,
 	XML_SCHEMA_ATTR_INFO_META_XSI_SCHEMA_LOC);
@@ -21494,7 +21572,7 @@
 	    NULL);
 	return;
     }
-    aidc->bubbleDepth = -1;
+    aidc->keyrefDepth = -1;
     aidc->def = idcDef;
     aidc->next = NULL;
     if (vctxt->aidcs == NULL)
@@ -21503,6 +21581,12 @@
 	aidc->next = vctxt->aidcs;
 	vctxt->aidcs = aidc;
     }
+    /*
+    * Save if we have keyrefs at all.
+    */
+    if ((vctxt->hasKeyrefs == 0) &&
+	(idcDef->type == XML_SCHEMA_TYPE_IDC_KEYREF))
+	vctxt->hasKeyrefs = 1;
 }
 
 /**
@@ -21511,7 +21595,7 @@
  *
  * Creates a new IDC binding.
  *
- * Returns the new binding in case of succeeded, NULL on internal errors.
+ * Returns the new IDC binding, NULL on internal errors.
  */
 static xmlSchemaPSVIIDCBindingPtr
 xmlSchemaIDCNewBinding(xmlSchemaIDCPtr idcDef)
@@ -21535,7 +21619,7 @@
  * @vctxt: the WXS validation context
  * @item: the IDC node table item
  *
- * The validation context is used to store an IDC node table items.
+ * The validation context is used to store IDC node table items.
  * They are stored to avoid copying them if IDC node-tables are merged
  * with corresponding parent IDC node-tables (bubbling).
  *
@@ -21652,7 +21736,7 @@
 }
 
 /**
- * xmlSchemaIDCAquireBinding:
+ * xmlSchemaIDCAcquireBinding:
  * @vctxt: the WXS validation context
  * @matcher: the IDC matcher
  *
@@ -21663,22 +21747,22 @@
  * Returns an IDC binding or NULL on internal errors.
  */
 static xmlSchemaPSVIIDCBindingPtr
-xmlSchemaIDCAquireBinding(xmlSchemaValidCtxtPtr vctxt,
+xmlSchemaIDCAcquireBinding(xmlSchemaValidCtxtPtr vctxt,
 			  xmlSchemaIDCMatcherPtr matcher)
 {
-    xmlSchemaNodeInfoPtr info;
+    xmlSchemaNodeInfoPtr ielem;
 
-    info = vctxt->elemInfos[matcher->depth];
+    ielem = vctxt->elemInfos[matcher->depth];
 
-    if (info->idcTable == NULL) {
-	info->idcTable = xmlSchemaIDCNewBinding(matcher->aidc->def);
-	if (info->idcTable == NULL)
+    if (ielem->idcTable == NULL) {
+	ielem->idcTable = xmlSchemaIDCNewBinding(matcher->aidc->def);
+	if (ielem->idcTable == NULL)
 	    return (NULL);
-	return(info->idcTable);
+	return(ielem->idcTable);
     } else {
 	xmlSchemaPSVIIDCBindingPtr bind = NULL;
 
-	bind = info->idcTable;
+	bind = ielem->idcTable;
 	do {
 	    if (bind->definition == matcher->aidc->def)
 		return(bind);
@@ -21694,6 +21778,15 @@
     return (NULL);
 }
 
+static xmlSchemaItemListPtr
+xmlSchemaIDCAcquireTargetList(xmlSchemaValidCtxtPtr vctxt ATTRIBUTE_UNUSED,
+			     xmlSchemaIDCMatcherPtr matcher)
+{
+    if (matcher->targets == NULL)
+	matcher->targets = xmlSchemaItemListCreate();
+    return(matcher->targets);
+}
+
 /**
  * xmlSchemaIDCFreeKey:
  * @key: the IDC key
@@ -21717,21 +21810,10 @@
 static void
 xmlSchemaIDCFreeBinding(xmlSchemaPSVIIDCBindingPtr bind)
 {
-    if (bind->nodeTable != NULL) {
-	if (bind->definition->type == XML_SCHEMA_TYPE_IDC_KEYREF) {
-	    int i;
-	    /*
-	    * Node-table items for keyrefs are not stored globally
-	    * to the validation context, since they are not bubbled.
-	    * We need to free them here.
-	    */
-	    for (i = 0; i < bind->nbNodes; i++) {
-		xmlFree(bind->nodeTable[i]->keys);
-		xmlFree(bind->nodeTable[i]);
-	    }
-	}
+    if (bind->nodeTable != NULL)
 	xmlFree(bind->nodeTable);
-    }
+    if (bind->dupls != NULL)
+	xmlSchemaItemListFree(bind->dupls);	
     xmlFree(bind);
 }
 
@@ -21771,7 +21853,25 @@
 	    for (i = 0; i < matcher->sizeKeySeqs; i++)
 		if (matcher->keySeqs[i] != NULL)
 		    xmlFree(matcher->keySeqs[i]);
-	    xmlFree(matcher->keySeqs);
+	    xmlFree(matcher->keySeqs);	    
+	}
+	if (matcher->targets != NULL) {
+	    if (matcher->idcType == XML_SCHEMA_TYPE_IDC_KEYREF) {
+		int i;
+		xmlSchemaPSVIIDCNodePtr idcNode;
+		/*
+		* Node-table items for keyrefs are not stored globally
+		* to the validation context, since they are not bubbled.
+		* We need to free them here.
+		*/
+		for (i = 0; i < matcher->targets->nbItems; i++) {
+		    idcNode =
+			(xmlSchemaPSVIIDCNodePtr) matcher->targets->items[i];
+		    xmlFree(idcNode->keys);
+		    xmlFree(idcNode);
+		}
+	    }
+	    xmlSchemaItemListFree(matcher->targets);
 	}
 	xmlFree(matcher);
 	matcher = next;
@@ -21848,7 +21948,7 @@
     sto->sel = sel;
     sto->nbHistory = 0;
     
-#if DEBUG_IDC
+#ifdef DEBUG_IDC
     xmlGenericError(xmlGenericErrorContext, "IDC:   STO push '%s'\n",
 	sto->sel->xpath);
 #endif
@@ -21877,7 +21977,7 @@
 
     if (nodeType == XML_ATTRIBUTE_NODE)
 	depth++;
-#if DEBUG_IDC
+#ifdef DEBUG_IDC
     {
 	xmlChar *str = NULL;
 	xmlGenericError(xmlGenericErrorContext, 
@@ -21893,7 +21993,7 @@
     first = vctxt->xpathStates;
     sto = first;
     while (sto != head) {
-#if DEBUG_IDC
+#ifdef DEBUG_IDC
 	if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_SELECTOR)
 	    xmlGenericError(xmlGenericErrorContext, "IDC:   ['%s'] selector '%s'\n", 
 		sto->matcher->aidc->def->name, sto->sel->xpath);
@@ -21918,7 +22018,7 @@
 	/*
 	* Full match.
 	*/
-#if DEBUG_IDC
+#ifdef DEBUG_IDC
 	xmlGenericError(xmlGenericErrorContext, "IDC:     "
 	    "MATCH\n");
 #endif
@@ -21956,7 +22056,7 @@
 	    * Activate state objects for the IDC fields of
 	    * the IDC selector.
 	    */
-#if DEBUG_IDC
+#ifdef DEBUG_IDC
 	    xmlGenericError(xmlGenericErrorContext, "IDC:     "
 		"activating field states\n");
 #endif
@@ -21971,7 +22071,7 @@
 	    /*
 	    * An IDC key node was found by the IDC field.
 	    */
-#if DEBUG_IDC
+#ifdef DEBUG_IDC
 	    xmlGenericError(xmlGenericErrorContext,
 		"IDC:     key found\n");
 #endif
@@ -22078,13 +22178,13 @@
     xmlSchemaIDCStateObjPtr sto, nextsto;
     int res, matchDepth;
     xmlSchemaPSVIIDCKeyPtr key = NULL;
-    xmlSchemaTypePtr type = vctxt->inode->typeDef;
+    xmlSchemaTypePtr type = vctxt->inode->typeDef, simpleType = NULL;
 
     if (vctxt->xpathStates == NULL)
 	return (0);
     sto = vctxt->xpathStates;
 
-#if DEBUG_IDC
+#ifdef DEBUG_IDC
     {
 	xmlChar *str = NULL;
 	xmlGenericError(xmlGenericErrorContext, 
@@ -22104,7 +22204,7 @@
 		"calling xmlStreamPop()");
 	    return (-1);
 	}
-#if DEBUG_IDC
+#ifdef DEBUG_IDC
 	xmlGenericError(xmlGenericErrorContext, "IDC:   stream pop '%s'\n",
 	    sto->sel->xpath);
 #endif
@@ -22121,8 +22221,31 @@
 	    continue;
 	}	
 	if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_FIELD) {
-	    if (! WXS_IS_SIMPLE(type)) {
+	    /*
+	    * NOTE: According to
+	    *   http://www.w3.org/Bugs/Public/show_bug.cgi?id=2198
+	    *   ... the simple-content of complex types is also allowed.
+	    */
+	    
+	    if (WXS_IS_COMPLEX(type)) {
+		if (WXS_HAS_SIMPLE_CONTENT(type)) {
+		    /*
+		    * Sanity check for complex types with simple content.
+		    */
+		    simpleType = type->contentTypeDef;
+		    if (simpleType == NULL) {
+			VERROR_INT("xmlSchemaXPathProcessHistory",
+			    "field resolves to a CT with simple content "
+			    "but the CT is missing the ST definition");
+			return (-1);
+		    }
+		} else
+		    simpleType = NULL;
+	    } else 
+		simpleType = type;
+	    if (simpleType == NULL) {
 		xmlChar *str = NULL;
+	
 		/*
 		* Not qualified if the field resolves to a node of non
 		* simple type.
@@ -22138,6 +22261,7 @@
 		sto->nbHistory--;
 		goto deregister_check;
 	    }
+	    
 	    if ((key == NULL) && (vctxt->inode->val == NULL)) {
 		/*
 		* Failed to provide the normalized value; maybe
@@ -22159,6 +22283,18 @@
 		* 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).
+		* 
+		* Element        Depth    Pos   List-entries
+		* <scope>          0              NULL
+		*   <bar>          1              NULL
+		*     <target/>    2       2      target
+		*   <bar>
+                * </scope>
+		*
+		* The size of the list is only dependant on the depth of
+		* the tree.
+		* An entry will be NULLed in selector_leave, i.e. when
+		* we hit the target's 
 		*/		    
 		pos = sto->depth - matcher->depth;
 		idx = sto->sel->index;
@@ -22211,33 +22347,30 @@
 		keySeq = matcher->keySeqs[pos];		    
 		if (keySeq == NULL) {	
 		    goto create_sequence;
-		} else {
-		    if (keySeq[idx] != NULL) {
-			xmlChar *str = 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.
-			*/
-			xmlSchemaCustomErr(ACTXT_CAST vctxt, 
-			    XML_SCHEMAV_CVC_IDC, NULL,
-			    WXS_BASIC_CAST matcher->aidc->def,
-			    "The XPath '%s' of a field of %s evaluates to a node-set "
-			    "with more than one member",
-			    sto->sel->xpath,
-			    xmlSchemaGetIDCDesignation(&str, matcher->aidc->def));
-			FREE_AND_NULL(str);
-			sto->nbHistory--;
-			goto deregister_check;
-		    } else {
-			goto create_key;
-		    }
-		}
+		} else if (keySeq[idx] != NULL) {
+		    xmlChar *str = 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.
+		    */
+		    xmlSchemaCustomErr(ACTXT_CAST vctxt, 
+			XML_SCHEMAV_CVC_IDC, NULL,
+			WXS_BASIC_CAST matcher->aidc->def,
+			"The XPath '%s' of a field of %s evaluates to a "
+			"node-set with more than one member",
+			sto->sel->xpath,
+			xmlSchemaGetIDCDesignation(&str, matcher->aidc->def));
+		    FREE_AND_NULL(str);
+		    sto->nbHistory--;
+		    goto deregister_check;
+		} else
+		    goto create_key;		
 		
 create_sequence:
 		/*
@@ -22256,7 +22389,7 @@
 		matcher->keySeqs[pos] = keySeq;
 create_key:
 		/*
-		* Created a key once per node only.
+		* Create a key once per node only.
 		*/  
 		if (key == NULL) {
 		    key = (xmlSchemaPSVIIDCKeyPtr) xmlMalloc(
@@ -22271,7 +22404,7 @@
 		    /*
 		    * Consume the compiled value.
 		    */
-		    key->type = type;
+		    key->type = simpleType;
 		    key->val = vctxt->inode->val;
 		    vctxt->inode->val = NULL;
 		    /*
@@ -22287,10 +22420,11 @@
 	} else if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_SELECTOR) {
 		
 	    xmlSchemaPSVIIDCKeyPtr **keySeq = NULL;
-	    xmlSchemaPSVIIDCBindingPtr bind;
+	    /* xmlSchemaPSVIIDCBindingPtr bind; */
 	    xmlSchemaPSVIIDCNodePtr ntItem;
 	    xmlSchemaIDCMatcherPtr matcher;
 	    xmlSchemaIDCPtr idc;
+	    xmlSchemaItemListPtr targets;
 	    int pos, i, j, nbKeys;
 	    /*
 	    * Here we have the following scenario:
@@ -22354,9 +22488,12 @@
 	    * Get the IDC binding from the matcher and check for
 	    * duplicate key-sequences.
 	    */
-	    bind = xmlSchemaIDCAquireBinding(vctxt, matcher);
+#if 0
+	    bind = xmlSchemaIDCAcquireBinding(vctxt, matcher);
+#endif
+	    targets = xmlSchemaIDCAcquireTargetList(vctxt, matcher);
 	    if ((idc->type != XML_SCHEMA_TYPE_IDC_KEYREF) && 
-		(bind->nbNodes != 0)) {
+		(targets->nbItems != 0)) {
 		xmlSchemaPSVIIDCKeyPtr ckey, bkey, *bkeySeq;
 		
 		i = 0;
@@ -22365,25 +22502,31 @@
 		* Compare the key-sequences, key by key.
 		*/
 		do {
-		    bkeySeq = bind->nodeTable[i]->keys;		    
+		    bkeySeq =
+			((xmlSchemaPSVIIDCNodePtr) targets->items[i])->keys;
 		    for (j = 0; j < nbKeys; j++) {
 			ckey = (*keySeq)[j];
 			bkey = bkeySeq[j];							
 			res = xmlSchemaAreValuesEqual(ckey->val, bkey->val);
 			if (res == -1) {
 			    return (-1);
-			} else if (res == 0)
+			} else if (res == 0) {
+			    /*
+			    * One of the keys differs, so the key-sequence
+			    * won't be equal; get out.
+			    */
 			    break;
+			}
 		    }
 		    if (res == 1) {
 			/*
-			* Duplicate found.
+			* Duplicate key-sequence found.
 			*/
 			break;
 		    }
 		    i++;
-		} while (i < bind->nbNodes);
-		if (i != bind->nbNodes) {
+		} while (i < targets->nbItems);
+		if (i != targets->nbItems) {
 		    xmlChar *str = NULL, *strB = NULL;
 		    /*   
 		    * TODO: Try to report the key-sequence.
@@ -22415,7 +22558,7 @@
 	    memset(ntItem, 0, sizeof(xmlSchemaPSVIIDCNode));
 	    
 	    /* 
-	    * Store the node-table item on global list.
+	    * Store the node-table item in a global list.
 	    */
 	    if (idc->type != XML_SCHEMA_TYPE_IDC_KEYREF) {
 		if (xmlSchemaIDCStoreNodeTableItem(vctxt, ntItem) == -1) {
@@ -22447,7 +22590,10 @@
 	    ntItem->nodeLine = vctxt->inode->nodeLine;
 	    ntItem->keys = *keySeq;
 	    *keySeq = NULL;
-	    if (xmlSchemaIDCAppendNodeTableItem(bind, ntItem) == -1) {		    
+#if 0
+	    if (xmlSchemaIDCAppendNodeTableItem(bind, ntItem) == -1) {
+#endif
+	    if (xmlSchemaItemListAdd(targets, ntItem) == -1) {
 		if (idc->type == XML_SCHEMA_TYPE_IDC_KEYREF) {
 		    /* 
 		    * Free the item, since keyref items won't be
@@ -22493,7 +22639,7 @@
 	* Deregister state objects if they reach the depth of creation.
 	*/
 	if ((sto->nbHistory == 0) && (sto->depth == depth)) {
-#if DEBUG_IDC
+#ifdef DEBUG_IDC
 	    xmlGenericError(xmlGenericErrorContext, "IDC:   STO pop '%s'\n",
 		sto->sel->xpath);
 #endif
@@ -22541,7 +22687,7 @@
     if (idc == NULL)
 	return (0);
     
-#if DEBUG_IDC
+#ifdef DEBUG_IDC
     {
 	xmlChar *str = NULL;
 	xmlGenericError(xmlGenericErrorContext, 
@@ -22562,13 +22708,17 @@
 	    * 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
+	    * references a key/unique IDC, the keyrefDepth will
 	    * be -1, indicating that no bubbles are needed.
 	    */
 	    refIdc = (xmlSchemaIDCPtr) idc->ref->item;
 	    if (refIdc != NULL) {
 		/*
-		* Lookup the augmented IDC.
+		* Remember that we have keyrefs on this node.
+		*/
+		vctxt->inode->hasKeyrefs = 1;
+		/*
+		* Lookup the referenced augmented IDC info.
 		*/
 		aidc = vctxt->aidcs;
 		while (aidc != NULL) {
@@ -22582,9 +22732,9 @@
 			"definition");
 		    return (-1);
 		}		
-		if ((aidc->bubbleDepth == -1) ||
-		    (vctxt->depth < aidc->bubbleDepth))
-		    aidc->bubbleDepth = vctxt->depth;
+		if ((aidc->keyrefDepth == -1) ||
+		    (vctxt->depth < aidc->keyrefDepth))
+		    aidc->keyrefDepth = vctxt->depth;
 	    }
 	}
 	/*
@@ -22621,7 +22771,8 @@
 	matcher->type = IDC_MATCHER;
 	matcher->depth = vctxt->depth;	
 	matcher->aidc = aidc;
-#if DEBUG_IDC	
+	matcher->idcType = aidc->def->type;
+#ifdef DEBUG_IDC	
 	xmlGenericError(xmlGenericErrorContext, "IDC:   register matcher\n");
 #endif 
 	/*
@@ -22636,6 +22787,191 @@
     return (0);
 }
 
+static int
+xmlSchemaIDCFillNodeTables(xmlSchemaValidCtxtPtr vctxt,
+			   xmlSchemaNodeInfoPtr ielem)
+{
+    xmlSchemaPSVIIDCBindingPtr bind;
+    int res, i, j, k, nbTargets, nbFields, nbDupls, nbNodeTable;
+    xmlSchemaPSVIIDCKeyPtr *keys, *ntkeys;
+    xmlSchemaPSVIIDCNodePtr *targets, *dupls;
+    
+    xmlSchemaIDCMatcherPtr matcher = ielem->idcMatchers;
+    /* vctxt->createIDCNodeTables */
+    while (matcher != NULL) {
+	/*
+	* Skip keyref IDCs and empty IDC target-lists.
+	*/
+	if ((matcher->aidc->def->type == XML_SCHEMA_TYPE_IDC_KEYREF) ||
+	    WXS_ILIST_IS_EMPTY(matcher->targets))
+	{
+	    matcher = matcher->next;
+	    continue;
+	}
+	/*
+	* If we _want_ the IDC node-table to be created in any case
+	* then do so. Otherwise create them only if keyrefs need them.
+	*/
+	if ((! vctxt->createIDCNodeTables) &&
+	    ((matcher->aidc->keyrefDepth == -1) ||
+	     (matcher->aidc->keyrefDepth > vctxt->depth)))
+	{
+	    matcher = matcher->next;
+	    continue;
+	}
+	/*
+	* Get/create the IDC binding on this element for the IDC definition.
+	*/
+	bind = xmlSchemaIDCAcquireBinding(vctxt, matcher);
+
+	if (! WXS_ILIST_IS_EMPTY(bind->dupls)) {
+	    dupls = (xmlSchemaPSVIIDCNodePtr *) bind->dupls->items;
+	    nbDupls = bind->dupls->nbItems;
+	} else {
+	    dupls = NULL;
+	    nbDupls = 0;	    
+	}
+	if (bind->nodeTable != NULL) {
+	    nbNodeTable = bind->nbNodes;
+	} else {
+	    nbNodeTable = 0;
+	}
+
+	if ((nbNodeTable == 0) && (nbDupls == 0)) {
+	    /*
+	    * Transfer all IDC target-nodes to the IDC node-table.
+	    */
+	    bind->nodeTable =
+		(xmlSchemaPSVIIDCNodePtr *) matcher->targets->items;		
+	    bind->sizeNodes = matcher->targets->sizeItems;
+	    bind->nbNodes = matcher->targets->nbItems;
+
+	    matcher->targets->items = NULL;
+	    matcher->targets->sizeItems = 0;
+	    matcher->targets->nbItems = 0;	    
+	} else {
+	    /*
+	    * Compare the key-sequences and add to the IDC node-table.
+	    */
+	    nbTargets = matcher->targets->nbItems;
+	    targets = (xmlSchemaPSVIIDCNodePtr *) matcher->targets->items;	
+	    nbFields = matcher->aidc->def->nbFields;
+	    i = 0;
+	    do {
+		keys = targets[i]->keys;
+		if (nbDupls) {			
+		    /*
+		    * Search in already found duplicates first.
+		    */
+		    j = 0;
+		    do {						
+			if (nbFields == 1) {
+			    res = xmlSchemaAreValuesEqual(keys[0]->val,
+				dupls[j]->keys[0]->val);
+			    if (res == -1)
+				goto internal_error;
+			    if (res == 1) {
+				/*
+				* Equal key-sequence.
+				*/
+				goto next_target;
+			    }
+			} else {
+			    res = 0;
+			    ntkeys = dupls[j]->keys;
+			    for (k = 0; k < nbFields; k++) {
+				res = xmlSchemaAreValuesEqual(keys[k]->val,
+				    ntkeys[k]->val);
+				if (res == -1)
+				    goto internal_error;
+				if (res == 0) {
+				    /*
+				    * One of the keys differs.
+				    */
+				    break;
+				}
+			    }
+			    if (res == 1) {
+				/*
+				* Equal key-sequence found.
+				*/
+				goto next_target;
+			    }
+			}
+			j++;
+		    } while (j < nbDupls);		    
+		}
+		if (nbNodeTable) {
+		    j = 0;
+		    do {						
+			if (nbFields == 1) {
+			    res = xmlSchemaAreValuesEqual(keys[0]->val,
+				bind->nodeTable[j]->keys[0]->val);
+			    if (res == -1)
+				goto internal_error;
+			    if (res == 0) {
+				/*
+				* The key-sequence differs.
+				*/
+				goto next_node_table_entry;
+			    }
+			} else {
+			    res = 0;
+			    ntkeys = bind->nodeTable[j]->keys;
+			    for (k = 0; k < nbFields; k++) {
+				res = xmlSchemaAreValuesEqual(keys[k]->val,
+				    ntkeys[k]->val);
+				if (res == -1)
+				    goto internal_error;
+				if (res == 0) {
+				    /*
+				    * One of the keys differs.
+				    */
+				    goto next_node_table_entry;
+				}
+			    }
+			}			
+			/*
+			* Add the duplicate to the list of duplicates.
+			*/
+			if (bind->dupls == NULL) {
+			    bind->dupls = xmlSchemaItemListCreate();
+			    if (bind->dupls == NULL)
+				goto internal_error;
+			}		    
+			if (xmlSchemaItemListAdd(bind->dupls, bind->nodeTable[j]) == -1)
+			    goto internal_error;
+			/*
+			* Remove the duplicate entry from the IDC node-table.
+			*/
+			bind->nodeTable[j] = bind->nodeTable[bind->nbNodes -1];
+			bind->nbNodes--;
+
+			goto next_target;
+
+next_node_table_entry:
+			j++;
+		    } while (j < nbNodeTable);
+		}
+		/*
+		* If everything is fine, then add the IDC target-node to
+		* the IDC node-table.
+		*/
+		if (xmlSchemaIDCAppendNodeTableItem(bind, targets[i]) == -1)
+		    goto internal_error;
+
+next_target:
+		i++;
+	    } while (i < nbTargets);
+	}
+	matcher = matcher->next;
+    }
+    return(0);
+
+internal_error:
+    return(-1);
+}
+
 /**
  * xmlSchemaBubbleIDCNodeTables: 
  * @depth: the current tree depth
@@ -22651,26 +22987,11 @@
 xmlSchemaBubbleIDCNodeTables(xmlSchemaValidCtxtPtr vctxt)
 {
     xmlSchemaPSVIIDCBindingPtr bind; /* IDC bindings of the current node. */
-    xmlSchemaPSVIIDCBindingPtr *parTable, parBind = NULL, lastParBind = NULL; /* parent IDC bindings. */
-    xmlSchemaPSVIIDCNodePtr node, parNode = NULL; /* node-table entries. */
-    xmlSchemaPSVIIDCKeyPtr key, parKey; /* keys of in a key-sequence. */
+    xmlSchemaPSVIIDCBindingPtr *parTable, parBind = NULL; /* parent IDC bindings. */
+    xmlSchemaPSVIIDCNodePtr node, parNode = NULL, *dupls, *parNodes; /* node-table entries. */
     xmlSchemaIDCAugPtr aidc;
-    int i, j, k, ret = 0, oldNum, newDupls;
-    int duplTop;
+    int i, j, k, ret = 0, nbFields, oldNum, oldDupls;
 
-    /*
-    * 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->inode->idcTable;        
     if (bind == NULL) {
 	/* Fine, no table, no bubbles. */
@@ -22682,136 +23003,160 @@
     * 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) {
-	    bind = bind->next;
-	    continue;
-	}
+	
+	if ((bind->nbNodes == 0) && WXS_ILIST_IS_EMPTY(bind->dupls))
+	    goto next_binding;
 	/*
 	* Check if the key/unique IDC table needs to be bubbled.
 	*/
-	aidc = vctxt->aidcs;
-	do {
-	    if (aidc->def == bind->definition) {
-		if ((aidc->bubbleDepth == -1) || 
-		    (aidc->bubbleDepth >= vctxt->depth)) {
-		    bind = bind->next;
-		    goto start_binding;
+	if (! vctxt->createIDCNodeTables) {
+	    aidc = vctxt->aidcs;
+	    do {
+		if (aidc->def == bind->definition) {
+		    if ((aidc->keyrefDepth == -1) || 
+			(aidc->keyrefDepth >= vctxt->depth)) {
+			goto next_binding;
+		    }
+		    break;
 		}
-		break;
-	    }
-	    aidc = aidc->next;
-	} while (aidc != NULL);
+		aidc = aidc->next;
+	    } while (aidc != NULL);
+	}
 
 	if (parTable != NULL)
 	    parBind = *parTable;
-	while (parBind != NULL) {
+	/*
+	* Search a matching parent binding for the
+	* IDC definition.
+	*/
+	while (parBind != NULL) {	    
+	    if (parBind->definition == bind->definition)
+		break;
+	    parBind = parBind->next;
+	}
+
+	if (parBind != NULL) {
 	    /*
-	    * Search a matching parent binding for the
-	    * IDC definition.
+	    * Compare every node-table entry of the child node, 
+	    * i.e. the key-sequence within, ...
 	    */
-	    if (parBind->definition == bind->definition) {
+	    oldNum = parBind->nbNodes; /* Skip newly added items. */
 
+	    if (! WXS_ILIST_IS_EMPTY(parBind->dupls)) {
+		oldDupls = parBind->dupls->nbItems;
+		dupls = (xmlSchemaPSVIIDCNodePtr *) parBind->dupls->items;
+	    } else {
+		dupls = NULL;
+		oldDupls = 0;		
+	    }
+	    
+	    parNodes = parBind->nodeTable;
+	    nbFields = bind->definition->nbFields;
+	    
+	    for (i = 0; i < bind->nbNodes; i++) {
+		node = bind->nodeTable[i];
+		if (node == NULL)
+		    continue;
 		/*
-		* Compare every node-table entry of the child node, 
-		* i.e. the key-sequence within, ...
+		* ...with every key-sequence of the parent node, already
+		* evaluated to be a duplicate key-sequence.
 		*/
-		oldNum = parBind->nbNodes; /* Skip newly added items. */
-		duplTop = oldNum + parBind->nbDupls;
-		newDupls = 0;
-
-		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->val,
-				    parKey->val);
-				if (ret == -1) {
-				    /* TODO: Internal error */
-				    return(-1);
-				} else if (ret == 0)
-				    break;
-
+		if (oldDupls) {
+		    j = 0; 
+		    while (j < oldDupls) {
+			if (nbFields == 1) {
+			    ret = xmlSchemaAreValuesEqual(
+				node->keys[0]->val,
+				dupls[j]->keys[0]->val);
+			    if (ret == -1)
+				goto internal_error;
+			    if (ret == 0) {
+				j++;
+				continue;
 			    }
-			    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->val,
-				parKey->val);
-			    if (ret == -1) {
-				/* TODO: Internal error */
-			    } else if (ret == 0)
-				break;
-
+			} else {
+			    parNode = dupls[j];
+			    for (k = 0; k < nbFields; k++) {
+				ret = xmlSchemaAreValuesEqual(
+				    node->keys[k]->val,
+				    parNode->keys[k]->val);
+				if (ret == -1)
+				    goto internal_error;
+				if (ret == 0)
+				    break;
+			    }
 			}
 			if (ret == 1)
-			    /*
-			    * The key-sequences are equal.
-			    */
+			    /* Duplicate found. */
+			    break;
+			j++;
+		    }
+		    if (j != oldDupls) {
+			/* Duplicate found. Skip this entry. */
+			continue;
+		    }
+		}		    
+		/*
+		* ... and with every key-sequence of the parent node.
+		*/
+		if (oldNum) {
+		    j = 0; 
+		    while (j < oldNum) {
+			if (nbFields == 1) {
+			    ret = xmlSchemaAreValuesEqual(
+				node->keys[0]->val,
+				parNodes[j]->keys[0]->val);
+			    if (ret == -1)
+				goto internal_error;
+			    if (ret == 0) {
+				j++;
+				continue;
+			    }
+			} else {
+			    parNode = parNodes[j];
+			    for (k = 0; k < nbFields; k++) {
+				ret = xmlSchemaAreValuesEqual(
+				    node->keys[k]->val,
+				    parNode->keys[k]->val);
+				if (ret == -1)
+				    goto internal_error;
+				if (ret == 0)
+				    break;
+			    }
+			}
+			if (ret == 1)
+			    /* Duplicate found. */
 			    break;
 			j++;
 		    }
 		    if (j != oldNum) {
 			/*
-			* Handle duplicates.
-			*/
-			newDupls++;
+			* Handle duplicates. Move the duplicate in
+			* the parent's node-table to the list of
+			* duplicates.
+			*/			
 			oldNum--;
 			parBind->nbNodes--;
 			/*
 			* Move last old item to pos of duplicate.
 			*/
-			parBind->nodeTable[j] = 
-			    parBind->nodeTable[oldNum];
+			parNodes[j] = parNodes[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];
+			    parNodes[oldNum] = 
+				parNodes[parBind->nbNodes];
 			}
-			/*
-			* Move duplicate to last pos of new/old items.
-			*/
-			parBind->nodeTable[parBind->nbNodes] = parNode;			
-			
+			if (parBind->dupls == NULL) {
+			    parBind->dupls = xmlSchemaItemListCreate();
+			    if (parBind->dupls == NULL)
+				goto internal_error;
+			}
+			xmlSchemaItemListAdd(parBind->dupls, parNode);			
 		    } else {
 			/*
 			* Add the node-table entry (node and key-sequence) of 
@@ -22823,10 +23168,10 @@
 			    if (parBind->nodeTable == NULL) {
 				xmlSchemaVErrMemory(NULL, 
 				    "allocating IDC list of node-table items", NULL);
-				return(-1);
+				goto internal_error;
 			    }
 			    parBind->sizeNodes = 1;
-			} else if (duplTop >= parBind->sizeNodes) {
+			} else if (parBind->nbNodes >= parBind->sizeNodes) {
 			    parBind->sizeNodes *= 2;
 			    parBind->nodeTable = (xmlSchemaPSVIIDCNodePtr *) 
 				xmlRealloc(parBind->nodeTable, parBind->sizeNodes * 
@@ -22834,71 +23179,93 @@
 			    if (parBind->nodeTable == NULL) {
 				xmlSchemaVErrMemory(NULL, 
 				    "re-allocating IDC list of node-table items", NULL);
-				return(-1);
+				goto internal_error;
 			    }
-			}
-			
-			/*
-			* 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->nodeTable[parBind->nbNodes++] = node;
 		    }
-		}
-		parBind->nbDupls += newDupls;
-		break;
-	    }
-	    if (parBind->next == NULL)
-		lastParBind = parBind;
-	    parBind = parBind->next;
-	}
-	if ((parBind == NULL) && (bind->nbNodes != 0)) {
+
+		}	
+		
+	    }	
+	} else {
 	    /*
 	    * 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);
+		goto internal_error;
+	    
+	    /*
+	    * TODO: Hmm, how to optimize the initial number of
+	    * allocated entries?
+	    */
+	    if (bind->nbNodes != 0) {
+		/*
+		* Add all IDC node-table entries.
+		*/
+		if (! vctxt->psviExposeIDCNodeTables) {
+		    /*
+		    * Just move the entries.
+		    * NOTE: this is quite save here, since
+		    * all the keyref lookups have already been
+		    * performed.
+		    */
+		    parBind->nodeTable = bind->nodeTable;
+		    bind->nodeTable = NULL;
+		    parBind->sizeNodes = bind->sizeNodes;
+		    bind->sizeNodes = 0;
+		    parBind->nbNodes = bind->nbNodes;
+		    bind->nbNodes = 0;
+		} else {
+		    /*
+		    * Copy the entries.
+		    */
+		    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);
+			goto internal_error;
+		    }
+		    parBind->sizeNodes = bind->nbNodes;
+		    parBind->nbNodes = bind->nbNodes;
+		    memcpy(parBind->nodeTable, bind->nodeTable,
+			bind->nbNodes * sizeof(xmlSchemaPSVIIDCNodePtr));
+		}
 	    }
-	    parBind->sizeNodes = bind->nbNodes;
-	    parBind->nbNodes = bind->nbNodes;
-	    memcpy(parBind->nodeTable, bind->nodeTable,
-		bind->nbNodes * sizeof(xmlSchemaPSVIIDCNodePtr));
+	    if (bind->dupls) {
+		/*
+		* Move the duplicates.
+		*/
+		if (parBind->dupls != NULL)
+		    xmlSchemaItemListFree(parBind->dupls);
+		parBind->dupls = bind->dupls;
+		bind->dupls = NULL;		
+	    }
 	    if (*parTable == NULL)
 		*parTable = parBind;
-	    else
-		lastParBind->next = parBind;
-	}
+	    else {
+		parBind->next = *parTable;
+		*parTable = parBind;
+	    }	   
+	}	
+
+next_binding:
 	bind = bind->next;
-    }  
+    }
     return (0);
+
+internal_error:
+    return(-1);
 }
 
 /**
@@ -22911,45 +23278,48 @@
 static int
 xmlSchemaCheckCVCIDCKeyRef(xmlSchemaValidCtxtPtr vctxt)
 {
-    xmlSchemaPSVIIDCBindingPtr refbind, bind;
-
-    refbind = vctxt->inode->idcTable;
+    xmlSchemaIDCMatcherPtr matcher;
+    xmlSchemaPSVIIDCBindingPtr bind;
+    
+    matcher = vctxt->inode->idcMatchers;
     /*
     * Find a keyref.
     */
-    while (refbind != NULL) {
-	if (refbind->definition->type == XML_SCHEMA_TYPE_IDC_KEYREF) {
-	    int i, j, k, res;
+    while (matcher != NULL) {
+	if ((matcher->idcType == XML_SCHEMA_TYPE_IDC_KEYREF) &&
+	    matcher->targets &&
+	    matcher->targets->nbItems)
+	{
+	    int i, j, k, res, nbFields, hasDupls;
 	    xmlSchemaPSVIIDCKeyPtr *refKeys, *keys;
-	    xmlSchemaPSVIIDCKeyPtr refKey, key;
 	    xmlSchemaPSVIIDCNodePtr refNode = NULL;
 
+	    nbFields = matcher->aidc->def->nbFields;
+
 	    /*
-	    * Find the referred key/unique.
+	    * Find the IDC node-table for the referenced IDC key/unique.
 	    */
 	    bind = vctxt->inode->idcTable;
-	    do {
-		if ((xmlSchemaIDCPtr) refbind->definition->ref->item == 
+	    while (bind != NULL) {
+		if ((xmlSchemaIDCPtr) matcher->aidc->def->ref->item == 
 		    bind->definition)
 		    break;
 		bind = bind->next;
-	    } while (bind != NULL);
-
+	    }
+	    hasDupls = (bind && bind->dupls && bind->dupls->nbItems) ? 1 : 0;
 	    /*
 	    * Search for a matching key-sequences.
 	    */
-	    for (i = 0; i < refbind->nbNodes; i++) {
+	    for (i = 0; i < matcher->targets->nbItems; i++) {
 		res = 0;
-		refNode = refbind->nodeTable[i];
+		refNode = matcher->targets->items[i];
 		if (bind != NULL) {
 		    refKeys = refNode->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->val,
-				refKey->val);
+			for (k = 0; k < nbFields; k++) {
+			    res = xmlSchemaAreValuesEqual(keys[k]->val,
+				refKeys[k]->val);
 			    if (res == 0)
 				break;
 			    else if (res == -1) {
@@ -22963,27 +23333,61 @@
 			    break;
 			}
 		    }
+		    if ((res == 0) && hasDupls) {
+			/*
+			* Search in duplicates
+			*/
+			for (j = 0; j < bind->dupls->nbItems; j++) {
+			    keys = ((xmlSchemaPSVIIDCNodePtr)
+				bind->dupls->items[j])->keys;
+			    for (k = 0; k < nbFields; k++) {
+				res = xmlSchemaAreValuesEqual(keys[k]->val,
+				    refKeys[k]->val);
+				if (res == 0)
+				    break;
+				else if (res == -1) {
+				    return (-1);
+				}
+			    }
+			    if (res == 1) {
+				/*
+				* Match in duplicates found.
+				*/
+				xmlChar *str = NULL, *strB = NULL;
+				xmlSchemaKeyrefErr(vctxt,
+				    XML_SCHEMAV_CVC_IDC, refNode,
+				    (xmlSchemaTypePtr) matcher->aidc->def,
+				    "More than one match found for "
+				    "key-sequence %s of keyref '%s'",
+				    xmlSchemaFormatIDCKeySequence(vctxt, &str,
+					refNode->keys, nbFields),
+				    xmlSchemaGetComponentQName(&strB,
+					matcher->aidc->def));
+				FREE_AND_NULL(str);
+				FREE_AND_NULL(strB);
+				break;
+			    }
+			}
+		    }
 		}
+		
 		if (res == 0) {
 		    xmlChar *str = NULL, *strB = NULL;
 		    xmlSchemaKeyrefErr(vctxt,
 			XML_SCHEMAV_CVC_IDC, refNode,
-			(xmlSchemaTypePtr) refbind->definition,
-			"No match found for key-sequence %s of key "
-			"reference '%s'",
+			(xmlSchemaTypePtr) matcher->aidc->def,
+			"No match found for key-sequence %s of keyref '%s'",
 			xmlSchemaFormatIDCKeySequence(vctxt, &str,
-			    refbind->nodeTable[i]->keys,
-			    refbind->definition->nbFields),
-			xmlSchemaFormatQName(&strB,
-			    refbind->definition->targetNamespace,
-			    refbind->definition->name));
+			    refNode->keys, nbFields),
+			xmlSchemaGetComponentQName(&strB, matcher->aidc->def));
 		    FREE_AND_NULL(str);
 		    FREE_AND_NULL(strB);
 		}
 	    }
 	}
-	refbind = refbind->next;
+	matcher = matcher->next;
     }
+    /* TODO: Return an error if any error encountered. */
     return (0);
 }
 
@@ -23105,6 +23509,7 @@
 static void
 xmlSchemaClearElemInfo(xmlSchemaNodeInfoPtr ielem)
 {
+    ielem->hasKeyrefs = 0;
     if (ielem->flags & XML_SCHEMA_NODE_INFO_FLAG_OWNED_NAMES) {
 	FREE_AND_NULL(ielem->localName);
 	FREE_AND_NULL(ielem->nsName);
@@ -23118,14 +23523,24 @@
 	ielem->value = NULL;
     }
     if (ielem->val != NULL) {
+	/*
+	* PSVI TODO: Be careful not to free it when the value is
+	* exposed via PSVI.
+	*/
 	xmlSchemaFreeValue(ielem->val);
 	ielem->val = NULL;
     }
     if (ielem->idcMatchers != NULL) {
+	/*
+	* URGENT OPTIMIZE TODO: Use a pool of IDC matchers.
+	*/
 	xmlSchemaIDCFreeMatcherList(ielem->idcMatchers);
 	ielem->idcMatchers = NULL;
     }
     if (ielem->idcTable != NULL) {
+	/*
+	* OPTIMIZE TODO: Use a pool of IDC tables??.
+	*/
 	xmlSchemaIDCFreeIDCTable(ielem->idcTable);
 	ielem->idcTable = NULL;
     }
@@ -23537,7 +23952,7 @@
 {
     int ret = 0, valNeeded = (retVal) ? 1 : 0;
     xmlSchemaValPtr val = NULL;
-    xmlSchemaWhitespaceValueType ws;
+    /* xmlSchemaWhitespaceValueType ws; */
     xmlChar *normValue = NULL;
 
 #define NORMALIZE(atype) \
@@ -23622,7 +24037,7 @@
 			value, &val, valNeeded);
 		    break;
 		default:
-		    ws = xmlSchemaGetWhiteSpaceFacetValue(type);
+		    /* ws = xmlSchemaGetWhiteSpaceFacetValue(type); */
 		    if (valNeeded)
 			ret = xmlSchemaValPredefTypeNodeNoNorm(biType,
 			    value, &val, NULL);
@@ -23639,7 +24054,7 @@
 			value, &val, valNeeded);
 		    break;
 		default:
-		    ws = xmlSchemaGetWhiteSpaceFacetValue(type);
+		    /* ws = xmlSchemaGetWhiteSpaceFacetValue(type); */
 		    if (valNeeded)
 			ret = xmlSchemaValPredefTypeNodeNoNorm(biType,
 			    value, &val, node);
@@ -24692,8 +25107,7 @@
 	    goto eval_idcs;
 	}
 
-	if (fixed) {
-	    int ws;
+	if (fixed) {	    
 	    /*
 	    * SPEC Attribute Locally Valid (Use) (cvc-au)
 	    * "For an attribute information item to be·valid·
@@ -24710,7 +25124,6 @@
 	    * (4) "The item's *actual* value· must match the *value* of
 	    * the {value constraint}, if it is present and fixed."
 	    */
-	    ws = xmlSchemaGetWhiteSpaceFacetValue(iattr->typeDef);
 	    if (iattr->val == NULL) {
 		/* VAL TODO: A value was not precomputed. */
 		TODO
@@ -25192,7 +25605,7 @@
 	* defined in Element Default Valid (Immediate) (§3.3.6). 
 	*/
 	/* 
-	* NOTE: 'local' above means types aquired by xsi:type.
+	* NOTE: 'local' above means types acquired by xsi:type.
 	* NOTE: Although the *canonical* value is stated, it is not
 	* relevant if canonical or not. Additionally XML Schema 1.1
 	* will removed this requirement as well.
@@ -25401,26 +25814,46 @@
     if (xmlSchemaXPathProcessHistory(vctxt, vctxt->depth) == -1)
 	goto internal_error;
     /*
-    * 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).
+    * MAYBE TODO:
+    * SPEC (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)."
     */
     /*
+    * PSVI TODO: If we expose IDC node-tables via PSVI then the tables
+    *   need to be built in any case.
+    *   We will currently build IDC node-tables and bubble them only if
+    *   keyrefs do exist.
+    */
+    
+    /*
+    * Add the current IDC target-nodes to the IDC node-tables.
+    */
+    if ((inode->idcMatchers != NULL) &&
+	(vctxt->hasKeyrefs || vctxt->createIDCNodeTables))
+    {
+	if (xmlSchemaIDCFillNodeTables(vctxt, inode) == -1)
+	    goto internal_error;
+    }
+    /*
     * Validate IDC keyrefs.
     */
-    if (xmlSchemaCheckCVCIDCKeyRef(vctxt) == -1)
-	goto internal_error;
+    if (vctxt->inode->hasKeyrefs)
+	if (xmlSchemaCheckCVCIDCKeyRef(vctxt) == -1)
+	    goto internal_error;
     /*
     * Merge/free the IDC table.
     */
     if (inode->idcTable != NULL) {
-#ifdef DEBUG_IDC
+#ifdef DEBUG_IDC_NODE_TABLE
 	xmlSchemaDebugDumpIDCTable(stdout,
 	    inode->nsName,
 	    inode->localName,
 	    inode->idcTable);
 #endif
-	if (vctxt->depth > 0) {
+	if ((vctxt->depth > 0) &&
+	    (vctxt->hasKeyrefs || vctxt->createIDCNodeTables))
+	{
 	    /*
 	    * Merge the IDC node table with the table of the parent node.
 	    */
@@ -25443,18 +25876,18 @@
 	return (0);
     }
     /*
-    * Reset the bubbleDepth if needed.
+    * Reset the keyrefDepth if needed.
     */
     if (vctxt->aidcs != NULL) {
 	xmlSchemaIDCAugPtr aidc = vctxt->aidcs;
 	do {
-	    if (aidc->bubbleDepth == vctxt->depth) {
+	    if (aidc->keyrefDepth == vctxt->depth) {
 		/*
-		* A bubbleDepth of a key/unique IDC matches the current
+		* A 'keyrefDepth' of a key/unique IDC matches the current
 		* depth, this means that we are leaving the scope of the
-		* top-most keyref IDC.
+		* top-most keyref IDC which refers to this IDC.
 		*/
-		aidc->bubbleDepth = -1;
+		aidc->keyrefDepth = -1;
 	    }
 	    aidc = aidc->next;
 	} while (aidc != NULL);
@@ -26490,12 +26923,19 @@
     if (vctxt == NULL)
         return;
 
+    /*
+    * TODO: Should we clear the flags?
+    *   Might be problematic if one reuses the context
+    *   and assumes that the options remain the same.
+    */
     vctxt->flags = 0;
     vctxt->validationRoot = NULL;
     vctxt->doc = NULL;
 #ifdef LIBXML_READER_ENABLED
     vctxt->reader = NULL;
 #endif
+    vctxt->hasKeyrefs = 0;    
+
     if (vctxt->value != NULL) {
         xmlSchemaFreeValue(vctxt->value);
 	vctxt->value = NULL;
@@ -26554,6 +26994,10 @@
     xmlSchemaItemListClear(vctxt->nodeQNames);
     /* Recreate the dict. */
     xmlDictFree(vctxt->dict);
+    /*
+    * TODO: Is is save to recreate it? Do we have a scenario
+    * where the user provides the dict?
+    */
     vctxt->dict = xmlDictCreate();
 }
 
@@ -26941,12 +27385,18 @@
 xmlSchemaPreRun(xmlSchemaValidCtxtPtr vctxt) {
     /*
     * Some initialization.
-    */
+    */    
     vctxt->err = 0;
     vctxt->nberrors = 0;
     vctxt->depth = -1;
     vctxt->skipDepth = -1;
     vctxt->xsiAssemble = 0;
+    vctxt->hasKeyrefs = 0;
+#ifdef ENABLE_IDC_NODE_TABLES
+    vctxt->createIDCNodeTables = 1;
+#else
+    vctxt->createIDCNodeTables = 0;
+#endif
     /*
     * Create a schema + parser if necessary.
     */