- debugXML.c hash.c tree.h valid.c : some changes related to
  the validation suport to improve speed with DocBook
- result/VC/OneID2 result/VC/OneID3 : this slightly changes
  the way validation errors get reported
Daniel
diff --git a/ChangeLog b/ChangeLog
index 6088f43..b111098 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Wed Apr 18 15:06:30 CEST 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+	* debugXML.c hash.c tree.h valid.c : some changes related to
+	  the validation suport to improve speed with DocBook
+	* result/VC/OneID2 result/VC/OneID3 : this slightly changes
+	  the way validation errors get reported
+
 Wed Apr 18 11:42:47 CEST 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
 	* HTMLparser.c HTMLtree.c: applied part of the patches provided
diff --git a/debugXML.c b/debugXML.c
index f9f1c8b..03b1128 100644
--- a/debugXML.c
+++ b/debugXML.c
@@ -239,6 +239,9 @@
     } else
 	fprintf(output, "PBM ELEMDECL noname!!!");
     switch (elem->etype) {
+	case XML_ELEMENT_TYPE_UNDEFINED: 
+	    fprintf(output, ", UNDEFINED");
+	    break;
 	case XML_ELEMENT_TYPE_EMPTY: 
 	    fprintf(output, ", EMPTY");
 	    break;
diff --git a/hash.c b/hash.c
index 45946ca..ec15745 100644
--- a/hash.c
+++ b/hash.c
@@ -27,6 +27,11 @@
 #include <libxml/hash.h>
 #include <libxml/xmlmemory.h>
 #include <libxml/parser.h>
+#include <libxml/xmlerror.h>
+
+#define MAX_HASH_LEN 8
+
+/* #define DEBUG_GROW */
 
 /*
  * A single entry in the hash table
@@ -55,13 +60,29 @@
  * Calculate the hash key
  */
 static unsigned long
-xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *string) {
+xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
+	          const xmlChar *name2, const xmlChar *name3) {
     unsigned long value = 0L;
     char ch;
     
-    while ((ch = *string++) != 0) {
-        /* value *= 31; */
-        value += (unsigned long)ch;
+    if (name != NULL) {
+	value += 30 * (*name);
+	while ((ch = *name++) != 0) {
+	    /* value *= 31; */
+	    value += (unsigned long)ch;
+	}
+    }
+    if (name2 != NULL) {
+	while ((ch = *name2++) != 0) {
+	    /* value *= 31; */
+	    value += (unsigned long)ch;
+	}
+    }
+    if (name3 != NULL) {
+	while ((ch = *name3++) != 0) {
+	    /* value *= 31; */
+	    value += (unsigned long)ch;
+	}
     }
     return (value % table->size);
 }
@@ -96,6 +117,77 @@
 }
 
 /**
+ * xmlHashGrow:
+ * @table: the hash table
+ * @size: the new size of the hash table
+ *
+ * resize the hash table
+ *
+ * Returns 0 in case of success, -1 in case of failure
+ */
+int
+xmlHashGrow(xmlHashTablePtr table, int size) {
+    unsigned long key;
+    int oldsize, i;
+    xmlHashEntryPtr iter, next;
+    struct _xmlHashEntry **oldtable;
+#ifdef DEBUG_GROW
+    unsigned long nbElem = 0;
+#endif
+  
+    if (table == NULL)
+	return(-1);
+    if (size < 8)
+        return(-1);
+    if (size > 8 * 2048)
+	return(-1);
+
+    oldsize = table->size;
+    oldtable = table->table;
+    if (oldtable == NULL)
+        return(-1);
+  
+    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
+    if (table->table == NULL) {
+	table->table = oldtable;
+	return(-1);
+    }
+    memset(table->table, 0, size * sizeof(xmlHashEntry));
+    table->size = size;
+
+    for (i = 0; i < oldsize; i++) {
+	iter = oldtable[i];
+	while (iter) {
+	    next = iter->next;
+
+	    /*
+	     * put back the entry in the new table
+	     */
+
+	    key = xmlHashComputeKey(table, iter->name, iter->name2,
+		                    iter->name3);
+	    iter->next = table->table[key];
+	    table->table[key] = iter;
+
+#ifdef DEBUG_GROW
+	    nbElem++;
+#endif
+
+	    iter = next;
+	}
+    }
+
+    xmlFree(oldtable);
+
+#ifdef DEBUG_GROW
+    xmlGenericError(xmlGenericErrorContext,
+	    "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
+#endif
+
+    return(0);
+}
+
+/**
  * xmlHashFree:
  * @table: the hash table
  * @f:  the deallocator function for items in the hash
@@ -116,14 +208,14 @@
 	    iter = table->table[i];
 	    while (iter) {
 		next = iter->next;
+		if (f)
+		    f(iter->payload, iter->name);
 		if (iter->name)
 		    xmlFree(iter->name);
 		if (iter->name2)
 		    xmlFree(iter->name2);
 		if (iter->name3)
 		    xmlFree(iter->name3);
-		if (f)
-		    f(iter->payload, iter->name);
 		iter->payload = NULL;
 		xmlFree(iter);
 		iter = next;
@@ -257,7 +349,7 @@
 xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
 	         const xmlChar *name2, const xmlChar *name3,
 		 void *userdata) {
-    unsigned long key;
+    unsigned long key, len = 0;
     xmlHashEntryPtr entry;
     xmlHashEntryPtr insert;
 
@@ -267,7 +359,7 @@
     /*
      * Check for duplicate and insertion location.
      */
-    key = xmlHashComputeKey(table, name);
+    key = xmlHashComputeKey(table, name, name2, name3);
     if (table->table[key] == NULL) {
 	insert = NULL;
     } else {
@@ -277,6 +369,7 @@
 		(xmlStrEqual(insert->name2, name2)) &&
 		(xmlStrEqual(insert->name3, name3)))
 		return(-1);
+	    len++;
 	}
 	if ((xmlStrEqual(insert->name, name)) &&
 	    (xmlStrEqual(insert->name2, name2)) &&
@@ -300,6 +393,10 @@
 	insert->next = entry;
     }
     table->nbElems++;
+
+    if (len > MAX_HASH_LEN)
+	xmlHashGrow(table, MAX_HASH_LEN * table->size);
+
     return(0);
 }
 
@@ -332,7 +429,7 @@
     /*
      * Check for duplicate and insertion location.
      */
-    key = xmlHashComputeKey(table, name);
+    key = xmlHashComputeKey(table, name, name2, name3);
     if (table->table[key] == NULL) {
 	insert = NULL;
     } else {
@@ -397,7 +494,7 @@
 	return(NULL);
     if (name == NULL)
 	return(NULL);
-    key = xmlHashComputeKey(table, name);
+    key = xmlHashComputeKey(table, name, name2, name3);
     for (entry = table->table[key]; entry != NULL; entry = entry->next) {
 	if ((xmlStrEqual(entry->name, name)) &&
 	    (xmlStrEqual(entry->name2, name2)) &&
@@ -544,8 +641,8 @@
  * Returns 0 if the removal succeeded and -1 in case of error or not found.
  */
 int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
-											 xmlHashDeallocator f) {
-	return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
+		       xmlHashDeallocator f) {
+    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
 }
 
 /**
@@ -561,8 +658,8 @@
  * Returns 0 if the removal succeeded and -1 in case of error or not found.
  */
 int xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
-												const xmlChar *name2, xmlHashDeallocator f) {
-	return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
+			const xmlChar *name2, xmlHashDeallocator f) {
+    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
 }
 
 /**
@@ -579,43 +676,42 @@
  * Returns 0 if the removal succeeded and -1 in case of error or not found.
  */
 int xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
-												const xmlChar *name2, const xmlChar *name3,
-												xmlHashDeallocator f) {
-	unsigned long key;
-	xmlHashEntryPtr entry;
-	xmlHashEntryPtr prev = NULL;
+    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
+    unsigned long key;
+    xmlHashEntryPtr entry;
+    xmlHashEntryPtr prev = NULL;
 
-	if (table == NULL || name == NULL)
-		return(-1);
+    if (table == NULL || name == NULL)
+        return(-1);
 
-	key = xmlHashComputeKey(table, name);
-	if (table->table[key] == NULL) {
-		return(-1);
-	} else {
-		for (entry = table->table[key]; entry != NULL; entry = entry->next) {
-			if (xmlStrEqual(entry->name, name) &&
-					xmlStrEqual(entry->name2, name2) &&
-					xmlStrEqual(entry->name3, name3)) {
-				if(f)
-					f(entry->payload, entry->name);
-				entry->payload = NULL;
-				if(entry->name)
-					xmlFree(entry->name);
-				if(entry->name2)
-					xmlFree(entry->name2);
-				if(entry->name3)
-					xmlFree(entry->name3);
-				if(prev)
-					prev->next = entry->next;
-				else
-					table->table[key] = entry->next;
-				xmlFree(entry);
-				table->nbElems--;
-				return(0);
-			}
-			prev = entry;
-		}
-		return(-1);
-	}
+    key = xmlHashComputeKey(table, name, name2, name3);
+    if (table->table[key] == NULL) {
+        return(-1);
+    } else {
+        for (entry = table->table[key]; entry != NULL; entry = entry->next) {
+            if (xmlStrEqual(entry->name, name) &&
+                    xmlStrEqual(entry->name2, name2) &&
+                    xmlStrEqual(entry->name3, name3)) {
+                if(f)
+                    f(entry->payload, entry->name);
+                entry->payload = NULL;
+                if(entry->name)
+                    xmlFree(entry->name);
+                if(entry->name2)
+                    xmlFree(entry->name2);
+                if(entry->name3)
+                    xmlFree(entry->name3);
+                if(prev)
+                    prev->next = entry->next;
+                else
+                    table->table[key] = entry->next;
+                xmlFree(entry);
+                table->nbElems--;
+                return(0);
+            }
+            prev = entry;
+        }
+        return(-1);
+    }
 }
 
diff --git a/include/libxml/tree.h b/include/libxml/tree.h
index 47e0212..ce86711 100644
--- a/include/libxml/tree.h
+++ b/include/libxml/tree.h
@@ -172,6 +172,7 @@
 };
 
 typedef enum {
+    XML_ELEMENT_TYPE_UNDEFINED = 0,
     XML_ELEMENT_TYPE_EMPTY = 1,
     XML_ELEMENT_TYPE_ANY,
     XML_ELEMENT_TYPE_MIXED,
diff --git a/result/VC/OneID2 b/result/VC/OneID2
index b1e2ed5..a67c893 100644
--- a/result/VC/OneID2
+++ b/result/VC/OneID2
@@ -1,6 +1,6 @@
+./test/VC/OneID2:3: validity error: Element doc has too may ID attributes defined : id
+<!ATTLIST doc id ID #IMPLIED>
+                            ^
 ./test/VC/OneID2:3: validity error: Element doc has 2 ID attribute defined in the internal subset : id
 <!ATTLIST doc id ID #IMPLIED>
                             ^
-./test/VC/OneID2:4: validity error: Element doc has too may ID attributes defined : val
-<!ELEMENT doc (#PCDATA)>
-                       ^
diff --git a/result/VC/OneID3 b/result/VC/OneID3
index d1742de..336caf8 100644
--- a/result/VC/OneID3
+++ b/result/VC/OneID3
@@ -1,3 +1,6 @@
-test/VC/dtds/doc.dtd:2: validity error: Element doc has ID attributes defined in the internal and external subset : val
+test/VC/dtds/doc.dtd:2: validity error: Element doc has too may ID attributes defined : val
+<!ATTLIST doc val ID #IMPLIED>
+                             ^
+test/VC/dtds/doc.dtd:2: validity error: Element doc has 2 ID attribute defined in the external subset : val
 <!ATTLIST doc val ID #IMPLIED>
                              ^
diff --git a/tree.h b/tree.h
index 47e0212..ce86711 100644
--- a/tree.h
+++ b/tree.h
@@ -172,6 +172,7 @@
 };
 
 typedef enum {
+    XML_ELEMENT_TYPE_UNDEFINED = 0,
     XML_ELEMENT_TYPE_EMPTY = 1,
     XML_ELEMENT_TYPE_ANY,
     XML_ELEMENT_TYPE_MIXED,
diff --git a/valid.c b/valid.c
index 822adeb..c3a0739 100644
--- a/valid.c
+++ b/valid.c
@@ -161,6 +161,8 @@
 	    (doc->extSubset == NULL)) return(0)
 
 xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name);
+static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
+	                           int create);
 xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
 
 /************************************************************************
@@ -507,6 +509,7 @@
 		  xmlElementContentPtr content) {
     xmlElementPtr ret;
     xmlElementTablePtr table;
+    xmlAttributePtr oldAttributes = NULL;
     xmlChar *ns, *uqname;
 
     if (dtd == NULL) {
@@ -575,38 +578,73 @@
         return(NULL);
     }
 
-    ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
-    if (ret == NULL) {
-	xmlGenericError(xmlGenericErrorContext,
-		"xmlAddElementDecl: out of memory\n");
-	return(NULL);
+    /*
+     * lookup old attributes inserted on an undefined element in the
+     * internal subset.
+     */
+    if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
+	ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
+	if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
+	    oldAttributes = ret->attributes;
+	    ret->attributes = NULL;
+	    xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
+	    xmlFreeElement(ret);
+	}
     }
-    memset(ret, 0, sizeof(xmlElement));
-    ret->type = XML_ELEMENT_DECL;
 
     /*
-     * fill the structure.
+     * The element may already be present if one of its attribute
+     * was registered first
+     */
+    ret = xmlHashLookup2(table, name, ns);
+    if (ret != NULL) {
+	if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
+	    /*
+	     * The element is already defined in this Dtd.
+	     */
+	    VERROR(ctxt->userData, "Redefinition of element %s\n", name);
+	    if (uqname != NULL)
+		xmlFree(uqname);
+	    return(NULL);
+	}
+    } else {
+	ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
+	if (ret == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlAddElementDecl: out of memory\n");
+	    return(NULL);
+	}
+	memset(ret, 0, sizeof(xmlElement));
+	ret->type = XML_ELEMENT_DECL;
+
+	/*
+	 * fill the structure.
+	 */
+	ret->name = xmlStrdup(name);
+	ret->prefix = ns;
+
+	/*
+	 * Validity Check:
+	 * Insertion must not fail
+	 */
+	if (xmlHashAddEntry2(table, name, ns, ret)) {
+	    /*
+	     * The element is already defined in this Dtd.
+	     */
+	    VERROR(ctxt->userData, "Redefinition of element %s\n", name);
+	    xmlFreeElement(ret);
+	    if (uqname != NULL)
+		xmlFree(uqname);
+	    return(NULL);
+	}
+    }
+
+    /*
+     * Finish to fill the structure.
      */
     ret->etype = type;
-    ret->name = xmlStrdup(name);
-    ret->prefix = ns;
     ret->content = xmlCopyElementContent(content);
-    ret->attributes = xmlScanAttributeDecl(dtd, name);
-
-    /*
-     * Validity Check:
-     * Insertion must not fail
-     */
-    if (xmlHashAddEntry2(table, name, ns, ret)) {
-	/*
-	 * The element is already defined in this Dtd.
-	 */
-	VERROR(ctxt->userData, "Redefinition of element %s\n", name);
-	xmlFreeElement(ret);
-	if (uqname != NULL)
-	    xmlFree(uqname);
-	return(NULL);
-    }
+    ret->attributes = oldAttributes;
 
     /*
      * Link it to the Dtd
@@ -910,7 +948,7 @@
 	    ret ++;
 	    if (ret > 1)
 		VERROR(ctxt->userData, 
-	       "Element %s has too may ID attributes defined : %s\n",
+	       "Element %s has too many ID attributes defined : %s\n",
 		       elem->name, cur->name);
 	}
 	cur = cur->nexth;
@@ -1078,7 +1116,7 @@
      * Validity Check:
      * Multiple ID per element
      */
-    elemDef = xmlGetDtdElementDesc(dtd, elem);
+    elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
     if (elemDef != NULL) {
         if ((type == XML_ATTRIBUTE_ID) &&
 	    (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
@@ -1999,16 +2037,80 @@
     xmlChar *uqname = NULL, *prefix = NULL;
 
     if (dtd == NULL) return(NULL);
-    if (dtd->elements == NULL) return(NULL);
+    if (dtd->elements == NULL)
+	return(NULL);
     table = (xmlElementTablePtr) dtd->elements;
 
     uqname = xmlSplitQName2(name, &prefix);
-    if (uqname != NULL) {
-	cur = xmlHashLookup2(table, uqname, prefix);
-	if (prefix != NULL) xmlFree(prefix);
-	if (uqname != NULL) xmlFree(uqname);
-    } else
-	cur = xmlHashLookup2(table, name, NULL);
+    if (uqname != NULL)
+        name = uqname;
+    cur = xmlHashLookup2(table, name, prefix);
+    if (prefix != NULL) xmlFree(prefix);
+    if (uqname != NULL) xmlFree(uqname);
+    return(cur);
+}
+/**
+ * xmlGetDtdElementDesc2:
+ * @dtd:  a pointer to the DtD to search
+ * @name:  the element name
+ * @create:  create an empty description if not found
+ *
+ * Search the Dtd for the description of this element
+ *
+ * returns the xmlElementPtr if found or NULL
+ */
+
+xmlElementPtr
+xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
+    xmlElementTablePtr table;
+    xmlElementPtr cur;
+    xmlChar *uqname = NULL, *prefix = NULL;
+
+    if (dtd == NULL) return(NULL);
+    if (dtd->elements == NULL) {
+	if (!create) 
+	    return(NULL);
+	/*
+	 * Create the Element table if needed.
+	 */
+	table = (xmlElementTablePtr) dtd->elements;
+	if (table == NULL) {
+	    table = xmlCreateElementTable();
+	    dtd->elements = (void *) table;
+	}
+	if (table == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlGetDtdElementDesc: Table creation failed!\n");
+	    return(NULL);
+	}
+    }
+    table = (xmlElementTablePtr) dtd->elements;
+
+    uqname = xmlSplitQName2(name, &prefix);
+    if (uqname != NULL)
+        name = uqname;
+    cur = xmlHashLookup2(table, name, prefix);
+    if ((cur == NULL) && (create)) {
+	cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
+	if (cur == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlGetDtdElementDesc: out of memory\n");
+	    return(NULL);
+	}
+	memset(cur, 0, sizeof(xmlElement));
+	cur->type = XML_ELEMENT_DECL;
+
+	/*
+	 * fill the structure.
+	 */
+	cur->name = xmlStrdup(name);
+	cur->prefix = xmlStrdup(prefix);
+	cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
+
+	xmlHashAddEntry2(table, name, prefix, cur);
+    }
+    if (prefix != NULL) xmlFree(prefix);
+    if (uqname != NULL) xmlFree(uqname);
     return(cur);
 }
 
@@ -2169,6 +2271,8 @@
 	elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
     if (elemDecl == NULL) return(-1);
     switch (elemDecl->etype) {
+	case XML_ELEMENT_TYPE_UNDEFINED:
+	    return(-1);
 	case XML_ELEMENT_TYPE_ELEMENT:
 	    return(0);
         case XML_ELEMENT_TYPE_EMPTY:
@@ -2788,22 +2892,25 @@
 
     /* VC: Unique Element Type Declaration */
     tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
-    if ((tst != NULL ) && (tst != elem)) {
+    if ((tst != NULL ) && (tst != elem) &&
+	(tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
 	VERROR(ctxt->userData, "Redefinition of element %s\n",
 	       elem->name);
 	ret = 0;
     }
     tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
-    if ((tst != NULL ) && (tst != elem)) {
+    if ((tst != NULL ) && (tst != elem) &&
+	(tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
 	VERROR(ctxt->userData, "Redefinition of element %s\n",
 	       elem->name);
 	ret = 0;
     }
 
-    /* One ID per Element Type */
+    /* One ID per Element Type
+     * already done when registering the attribute
     if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
 	ret = 0;
-    }
+    } */
     return(ret);
 }
 
@@ -3426,6 +3533,10 @@
 
     /* Check taht the element content matches the definition */
     switch (elemDecl->etype) {
+        case XML_ELEMENT_TYPE_UNDEFINED:
+	    VERROR(ctxt->userData, "No declaration for element %s\n",
+		   elem->name);
+	    return(0);
         case XML_ELEMENT_TYPE_EMPTY:
 	    if (elem->children != NULL) {
 		VERROR(ctxt->userData,