Huge commit: 1.5.0, XML validation, Xpath, bugfixes, examples .... Daniel
diff --git a/valid.c b/valid.c
index 87af873..b23824f 100644
--- a/valid.c
+++ b/valid.c
@@ -12,6 +12,20 @@
 #include <string.h>
 #include "valid.h"
 #include "parser.h"
+#include "parserInternals.h"
+
+#define VERROR							\
+   if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
+
+#define VWARNING						\
+   if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
+
+#define CHECK_DTD						\
+   if (doc == NULL) return(0);					\
+   else if (doc->intSubset == NULL) return(0)
+
+xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const CHAR *name);
+xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const CHAR *elem);
 
 /****************************************************************
  *								*
@@ -169,6 +183,68 @@
     }
 }
 
+/**
+ * xmlSprintfElementContent:
+ * @buf:  an output buffer
+ * @content:  An element table
+ * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
+ *
+ * This will dump the content of the element content definition
+ * Intended just for the debug routine
+ */
+void
+xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int glob) {
+    if (content == NULL) return;
+    if (glob) strcat(buf, "(");
+    switch (content->type) {
+        case XML_ELEMENT_CONTENT_PCDATA:
+            strcat(buf, "#PCDATA");
+	    break;
+	case XML_ELEMENT_CONTENT_ELEMENT:
+	    strcat(buf, content->name);
+	    break;
+	case XML_ELEMENT_CONTENT_SEQ:
+	    if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
+	        (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
+		xmlSprintfElementContent(buf, content->c1, 1);
+	    else
+		xmlSprintfElementContent(buf, content->c1, 0);
+            strcat(buf, " , ");
+	    if (content->c2->type == XML_ELEMENT_CONTENT_OR)
+		xmlSprintfElementContent(buf, content->c2, 1);
+	    else
+		xmlSprintfElementContent(buf, content->c2, 0);
+	    break;
+	case XML_ELEMENT_CONTENT_OR:
+	    if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
+	        (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
+		xmlSprintfElementContent(buf, content->c1, 1);
+	    else
+		xmlSprintfElementContent(buf, content->c1, 0);
+            strcat(buf, " | ");
+	    if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
+		xmlSprintfElementContent(buf, content->c2, 1);
+	    else
+		xmlSprintfElementContent(buf, content->c2, 0);
+	    break;
+    }
+    if (glob)
+        strcat(buf, ")");
+    switch (content->ocur) {
+        case XML_ELEMENT_CONTENT_ONCE:
+	    break;
+        case XML_ELEMENT_CONTENT_OPT:
+	    strcat(buf, "?");
+	    break;
+        case XML_ELEMENT_CONTENT_MULT:
+	    strcat(buf, "*");
+	    break;
+        case XML_ELEMENT_CONTENT_PLUS:
+	    strcat(buf, "+");
+	    break;
+    }
+}
+
 /****************************************************************
  *								*
  *	Registration of DTD declarations			*
@@ -195,8 +271,8 @@
     }
     ret->max_elements = XML_MIN_ELEMENT_TABLE;
     ret->nb_elements = 0;
-    ret->table = (xmlElementPtr ) 
-         malloc(ret->max_elements * sizeof(xmlElement));
+    ret->table = (xmlElementPtr *) 
+         malloc(ret->max_elements * sizeof(xmlElementPtr));
     if (ret == NULL) {
         fprintf(stderr, "xmlCreateElementTable : malloc(%ld) failed\n",
 	        ret->max_elements * (long)sizeof(xmlElement));
@@ -219,8 +295,8 @@
  * Returns NULL if not, othervise the entity
  */
 xmlElementPtr
-xmlAddElementDecl(xmlDtdPtr dtd, const CHAR *name, int type, 
-                  xmlElementContentPtr content) {
+xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *name,
+                  int type, xmlElementContentPtr content) {
     xmlElementPtr ret, cur;
     xmlElementTablePtr table;
     int i;
@@ -283,13 +359,12 @@
      * Search the DTD for previous declarations of the ELEMENT
      */
     for (i = 0;i < table->nb_elements;i++) {
-        cur = &table->table[i];
+        cur = table->table[i];
 	if (!xmlStrcmp(cur->name, name)) {
 	    /*
 	     * The element is already defined in this Dtd.
 	     */
-	    fprintf(stderr,
-		    "xmlAddElementDecl: %s already defined\n", name);
+	    VERROR(ctxt->userData, "Redefinition of element %s\n", name);
 	    return(NULL);
 	}
     }
@@ -302,14 +377,19 @@
 	 * need more elements.
 	 */
 	table->max_elements *= 2;
-	table->table = (xmlElementPtr) 
-	    realloc(table->table, table->max_elements * sizeof(xmlElement));
-	if (table->table) {
+	table->table = (xmlElementPtr *) 
+	    realloc(table->table, table->max_elements * sizeof(xmlElementPtr));
+	if (table->table == NULL) {
 	    fprintf(stderr, "xmlAddElementDecl: out of memory\n");
 	    return(NULL);
 	}
     }
-    ret = &table->table[table->nb_elements];
+    ret = (xmlElementPtr) malloc(sizeof(xmlElement));
+    if (ret == NULL) {
+	fprintf(stderr, "xmlAddElementDecl: out of memory\n");
+	return(NULL);
+    }
+    table->table[table->nb_elements] = ret;
 
     /*
      * fill the structure.
@@ -317,6 +397,7 @@
     ret->type = type;
     ret->name = xmlStrdup(name);
     ret->content = xmlCopyElementContent(content);
+    ret->attributes = xmlScanAttributeDecl(dtd, name);
     table->nb_elements++;
 
     return(ret);
@@ -335,6 +416,7 @@
     if (elem->name != NULL)
 	free((CHAR *) elem->name);
     memset(elem, -1, sizeof(xmlElement));
+    free(elem);
 }
 
 /**
@@ -350,7 +432,7 @@
     if (table == NULL) return;
 
     for (i = 0;i < table->nb_elements;i++) {
-        xmlFreeElement(&table->table[i]);
+        xmlFreeElement(table->table[i]);
     }
     free(table->table);
     free(table);
@@ -375,8 +457,8 @@
         fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
 	return(NULL);
     }
-    ret->table = (xmlElementPtr) malloc(table->max_elements *
-                                         sizeof(xmlElement));
+    ret->table = (xmlElementPtr *) malloc(table->max_elements *
+                                         sizeof(xmlElementPtr));
     if (ret->table == NULL) {
         fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
 	free(ret);
@@ -385,14 +467,22 @@
     ret->max_elements = table->max_elements;
     ret->nb_elements = table->nb_elements;
     for (i = 0;i < ret->nb_elements;i++) {
-	cur = &ret->table[i];
-	ent = &table->table[i];
+	cur = (xmlElementPtr) malloc(sizeof(xmlElement));
+	if (cur == NULL) {
+	    fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
+	    free(ret);
+	    free(ret->table);
+	    return(NULL);
+	}
+	ret->table[i] = cur;
+	ent = table->table[i];
 	cur->type = ent->type;
 	if (ent->name != NULL)
 	    cur->name = xmlStrdup(ent->name);
 	else
 	    cur->name = NULL;
 	cur->content = xmlCopyElementContent(ent->content);
+	cur->attributes = NULL;
     }
     return(ret);
 }
@@ -412,7 +502,7 @@
     if (table == NULL) return;
 
     for (i = 0;i < table->nb_elements;i++) {
-        cur = &table->table[i];
+        cur = table->table[i];
         switch (cur->type) {
 	    case XML_ELEMENT_TYPE_EMPTY:
 	        xmlBufferWriteChar(buf, "<!ELEMENT ");
@@ -514,6 +604,26 @@
 }
 
 /**
+ * xmlDumpEnumeration:
+ * @buf:  the XML buffer output
+ * @enum:  An enumeration
+ *
+ * This will dump the content of the enumeration
+ */
+void
+xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
+    if (cur == NULL)  return;
+    
+    xmlBufferWriteCHAR(buf, cur->name);
+    if (cur->next == NULL)
+	xmlBufferWriteChar(buf, ")");
+    else {
+	xmlBufferWriteChar(buf, " | ");
+	xmlDumpEnumeration(buf, cur->next);
+    }
+}
+
+/**
  * xmlCreateAttributeTable:
  *
  * create and initialize an empty attribute hash table.
@@ -534,20 +644,89 @@
     }
     ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
     ret->nb_attributes = 0;
-    ret->table = (xmlAttributePtr ) 
-         malloc(ret->max_attributes * sizeof(xmlAttribute));
+    ret->table = (xmlAttributePtr *) 
+         malloc(ret->max_attributes * sizeof(xmlAttributePtr));
     if (ret == NULL) {
         fprintf(stderr, "xmlCreateAttributeTable : malloc(%ld) failed\n",
-	        ret->max_attributes * (long)sizeof(xmlAttribute));
+	        ret->max_attributes * (long)sizeof(xmlAttributePtr));
 	free(ret);
         return(NULL);
     }
     return(ret);
 }
 
+/**
+ * xmlScanAttributeDecl:
+ * @dtd:  pointer to the DTD
+ * @elem:  the element name
+ *
+ * When inserting a new element scan the DtD for existing attributes
+ * for taht element and initialize the Attribute chain
+ *
+ * Returns the pointer to the first attribute decl in the chain,
+ *         possibly NULL.
+ */
+xmlAttributePtr
+xmlScanAttributeDecl(xmlDtdPtr dtd, const CHAR *elem) {
+    xmlAttributePtr ret = NULL;
+    xmlAttributeTablePtr table;
+    int i;
+
+    if (dtd == NULL) {
+        fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
+	return(NULL);
+    }
+    if (elem == NULL) {
+        fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
+	return(NULL);
+    }
+    table = dtd->attributes;
+    if (table == NULL) 
+        return(NULL);
+
+    for (i = 0;i < table->nb_attributes;i++) {
+        if (!xmlStrcmp(table->table[i]->elem, elem)) {
+	    table->table[i]->next = ret;
+	    ret = table->table[i];
+	}
+    }
+    return(ret);
+}
+
+/**
+ * xmlScanIDAttributeDecl:
+ * @ctxt:  the validation context
+ * @elem:  the element name
+ *
+ * Veryfy that the element don't have too many ID attributes
+ * declared.
+ *
+ * Returns the number of ID attributes found.
+ */
+int
+xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
+    xmlAttributePtr cur;
+    int ret = 0;
+
+    if (elem == NULL) return(0);
+    cur = elem->attributes;
+    while (cur != NULL) {
+        if (cur->type == XML_ATTRIBUTE_ID) {
+	    ret ++;
+	    if (ret > 1)
+		VERROR(ctxt->userData, 
+	       "Element %s has too may ID attributes defined : %s\n",
+		       elem->name, cur->name);
+	}
+	cur = cur->next;
+    }
+    return(ret);
+}
+
 
 /**
  * xmlAddAttributeDecl:
+ * @ctxt:  the validation context
  * @dtd:  pointer to the DTD
  * @elem:  the element name
  * @name:  the attribute name
@@ -561,11 +740,12 @@
  * Returns NULL if not, othervise the entity
  */
 xmlAttributePtr
-xmlAddAttributeDecl(xmlDtdPtr dtd, const CHAR *elem, const CHAR *name,
-                    int type, int def, const CHAR *defaultValue,
-		    xmlEnumerationPtr tree) {
+xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *elem,
+                    const CHAR *name, int type, int def,
+		    const CHAR *defaultValue, xmlEnumerationPtr tree) {
     xmlAttributePtr ret, cur;
     xmlAttributeTablePtr table;
+    xmlElementPtr elemDef;
     int i;
 
     if (dtd == NULL) {
@@ -623,7 +803,7 @@
      * Search the DTD for previous declarations of the ATTLIST
      */
     for (i = 0;i < table->nb_attributes;i++) {
-        cur = &table->table[i];
+        cur = table->table[i];
 	if ((!xmlStrcmp(cur->name, name)) && (!xmlStrcmp(cur->elem, elem))) {
 	    /*
 	     * The attribute is already defined in this Dtd.
@@ -641,14 +821,20 @@
 	 * need more attributes.
 	 */
 	table->max_attributes *= 2;
-	table->table = (xmlAttributePtr) 
-	    realloc(table->table, table->max_attributes * sizeof(xmlAttribute));
-	if (table->table) {
+	table->table = (xmlAttributePtr *) 
+	    realloc(table->table, table->max_attributes * 
+	            sizeof(xmlAttributePtr));
+	if (table->table == NULL) {
 	    fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
 	    return(NULL);
 	}
     }
-    ret = &table->table[table->nb_attributes];
+    ret = (xmlAttributePtr) malloc(sizeof(xmlAttribute));
+    if (ret == NULL) {
+	fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
+	return(NULL);
+    }
+    table->table[table->nb_attributes] = ret;
 
     /*
      * fill the structure.
@@ -662,6 +848,16 @@
 	ret->defaultValue = xmlStrdup(defaultValue);
     else
         ret->defaultValue = NULL;
+    elemDef = xmlGetDtdElementDesc(dtd, elem);
+    if (elemDef != NULL) {
+        if ((type == XML_ATTRIBUTE_ID) &&
+	    (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
+	    VERROR(ctxt->userData, 
+	   "Element %s has too may ID attributes defined : %s\n",
+		   elem, name);
+        ret->next = elemDef->attributes;
+        elemDef->attributes = ret;
+    }
     table->nb_attributes++;
 
     return(ret);
@@ -685,6 +881,7 @@
     if (attr->defaultValue != NULL)
 	free((CHAR *) attr->defaultValue);
     memset(attr, -1, sizeof(xmlAttribute));
+    free(attr);
 }
 
 /**
@@ -700,7 +897,7 @@
     if (table == NULL) return;
 
     for (i = 0;i < table->nb_attributes;i++) {
-        xmlFreeAttribute(&table->table[i]);
+        xmlFreeAttribute(table->table[i]);
     }
     free(table->table);
     free(table);
@@ -725,8 +922,8 @@
         fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
 	return(NULL);
     }
-    ret->table = (xmlAttributePtr) malloc(table->max_attributes *
-                                         sizeof(xmlAttribute));
+    ret->table = (xmlAttributePtr *) malloc(table->max_attributes *
+                                          sizeof(xmlAttributePtr));
     if (ret->table == NULL) {
         fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
 	free(ret);
@@ -735,8 +932,15 @@
     ret->max_attributes = table->max_attributes;
     ret->nb_attributes = table->nb_attributes;
     for (i = 0;i < ret->nb_attributes;i++) {
-	cur = &ret->table[i];
-	attr = &table->table[i];
+	attr = table->table[i];
+	cur = (xmlAttributePtr) malloc(sizeof(xmlAttribute));
+	if (cur == NULL) {
+	    fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
+	    free(ret);
+	    free(ret->table);
+	    return(NULL);
+	}
+	ret->table[i] = cur;
 	cur->type = attr->type;
 	cur->def = attr->def;
 	cur->tree = xmlCopyEnumeration(attr->tree);
@@ -752,6 +956,7 @@
 	    cur->defaultValue = xmlStrdup(attr->defaultValue);
 	else
 	    cur->defaultValue = NULL;
+	/* NEED to rebuild the next chain !!!!!! */
     }
     return(ret);
 }
@@ -771,7 +976,7 @@
     if (table == NULL) return;
 
     for (i = 0;i < table->nb_attributes;i++) {
-        cur = &table->table[i];
+        cur = table->table[i];
 	xmlBufferWriteChar(buf, "<!ATTLIST ");
 	xmlBufferWriteCHAR(buf, cur->elem);
 	xmlBufferWriteChar(buf, " ");
@@ -802,10 +1007,12 @@
 		xmlBufferWriteChar(buf, " NMTOKENS");
                 break;
             case XML_ATTRIBUTE_ENUMERATION:
-                xmlBufferWriteChar(buf, " (pbm)");
+                xmlBufferWriteChar(buf, " (");
+		xmlDumpEnumeration(buf, cur->tree);
                 break;
             case XML_ATTRIBUTE_NOTATION:
-                xmlBufferWriteChar(buf, " NOTATION (pbm)");
+                xmlBufferWriteChar(buf, " NOTATION (");
+		xmlDumpEnumeration(buf, cur->tree);
                 break;
 	    default:
 	        fprintf(stderr,
@@ -820,20 +1027,19 @@
                 break;
             case XML_ATTRIBUTE_IMPLIED:
 		xmlBufferWriteChar(buf, " #IMPLIED");
-		if (cur->defaultValue != NULL) {
-		    xmlBufferWriteChar(buf, " ");
-		    xmlBufferWriteQuotedString(buf, cur->defaultValue);
-		}
                 break;
             case XML_ATTRIBUTE_FIXED:
-		xmlBufferWriteChar(buf, " #FIXED ");
-		xmlBufferWriteQuotedString(buf, cur->defaultValue);
+		xmlBufferWriteChar(buf, " #FIXED");
                 break;
 	    default:
 	        fprintf(stderr,
 		    "xmlDumpAttributeTable: internal: unknown default %d\n",
 		        cur->def);
         }
+	if (cur->defaultValue != NULL) {
+	    xmlBufferWriteChar(buf, " ");
+	    xmlBufferWriteQuotedString(buf, cur->defaultValue);
+	}
         xmlBufferWriteChar(buf, ">\n");
     }
 }
@@ -864,8 +1070,8 @@
     }
     ret->max_notations = XML_MIN_NOTATION_TABLE;
     ret->nb_notations = 0;
-    ret->table = (xmlNotationPtr ) 
-         malloc(ret->max_notations * sizeof(xmlNotation));
+    ret->table = (xmlNotationPtr *) 
+         malloc(ret->max_notations * sizeof(xmlNotationPtr));
     if (ret == NULL) {
         fprintf(stderr, "xmlCreateNotationTable : malloc(%ld) failed\n",
 	        ret->max_notations * (long)sizeof(xmlNotation));
@@ -879,6 +1085,7 @@
 /**
  * xmlAddNotationDecl:
  * @dtd:  pointer to the DTD
+ * @ctxt:  the validation context
  * @name:  the entity name
  * @PublicID:  the public identifier or NULL
  * @SystemID:  the system identifier or NULL
@@ -888,8 +1095,8 @@
  * Returns NULL if not, othervise the entity
  */
 xmlNotationPtr
-xmlAddNotationDecl(xmlDtdPtr dtd, const CHAR *name, const CHAR *PublicID,
-                   const CHAR *SystemID) {
+xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *name,
+                   const CHAR *PublicID, const CHAR *SystemID) {
     xmlNotationPtr ret, cur;
     xmlNotationTablePtr table;
     int i;
@@ -922,7 +1129,7 @@
      * Search the DTD for previous declarations of the ATTLIST
      */
     for (i = 0;i < table->nb_notations;i++) {
-        cur = &table->table[i];
+        cur = table->table[i];
 	if (!xmlStrcmp(cur->name, name)) {
 	    /*
 	     * The notation is already defined in this Dtd.
@@ -940,14 +1147,20 @@
 	 * need more notations.
 	 */
 	table->max_notations *= 2;
-	table->table = (xmlNotationPtr) 
-	    realloc(table->table, table->max_notations * sizeof(xmlNotation));
-	if (table->table) {
+	table->table = (xmlNotationPtr *) 
+	    realloc(table->table, table->max_notations *
+	            sizeof(xmlNotationPtr));
+	if (table->table == NULL) {
 	    fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
 	    return(NULL);
 	}
     }
-    ret = &table->table[table->nb_notations];
+    ret = (xmlNotationPtr) malloc(sizeof(xmlNotation));
+    if (ret == NULL) {
+	fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
+	return(NULL);
+    }
+    table->table[table->nb_notations] = ret;
 
     /*
      * fill the structure.
@@ -982,6 +1195,7 @@
     if (nota->SystemID != NULL)
 	free((CHAR *) nota->SystemID);
     memset(nota, -1, sizeof(xmlNotation));
+    free(nota);
 }
 
 /**
@@ -997,7 +1211,7 @@
     if (table == NULL) return;
 
     for (i = 0;i < table->nb_notations;i++) {
-        xmlFreeNotation(&table->table[i]);
+        xmlFreeNotation(table->table[i]);
     }
     free(table->table);
     free(table);
@@ -1022,8 +1236,8 @@
         fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
 	return(NULL);
     }
-    ret->table = (xmlNotationPtr) malloc(table->max_notations *
-                                         sizeof(xmlNotation));
+    ret->table = (xmlNotationPtr *) malloc(table->max_notations *
+                                         sizeof(xmlNotationPtr));
     if (ret->table == NULL) {
         fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
 	free(ret);
@@ -1032,8 +1246,15 @@
     ret->max_notations = table->max_notations;
     ret->nb_notations = table->nb_notations;
     for (i = 0;i < ret->nb_notations;i++) {
-	cur = &ret->table[i];
-	nota = &table->table[i];
+	cur = (xmlNotationPtr) malloc(sizeof(xmlNotation));
+	if (cur == NULL) {
+	    fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
+	    free(ret);
+	    free(ret->table);
+	    return(NULL);
+	}
+	ret->table[i] = cur;
+	nota = table->table[i];
 	if (nota->name != NULL)
 	    cur->name = xmlStrdup(nota->name);
 	else
@@ -1065,7 +1286,7 @@
     if (table == NULL) return;
 
     for (i = 0;i < table->nb_notations;i++) {
-        cur = &table->table[i];
+        cur = table->table[i];
 	xmlBufferWriteChar(buf, "<!NOTATION ");
 	xmlBufferWriteCHAR(buf, cur->name);
 	if (cur->PublicID != NULL) {
@@ -1082,3 +1303,1070 @@
         xmlBufferWriteChar(buf, " >\n");
     }
 }
+
+/************************************************************************
+ *									*
+ *		Routines for validity checking				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlGetDtdElementDesc:
+ * @dtd:  a pointer to the DtD to search
+ * @name:  the element name
+ *
+ * Search the Dtd for the description of this element
+ *
+ * returns the xmlElementPtr if found or NULL
+ */
+
+xmlElementPtr
+xmlGetDtdElementDesc(xmlDtdPtr dtd, const CHAR *name) {
+    xmlElementTablePtr table;
+    xmlElementPtr cur;
+    int i;
+
+    if (dtd == NULL) return(NULL);
+    if (dtd->elements == NULL) return(NULL);
+    table = dtd->elements;
+
+    for (i = 0;i < table->nb_elements;i++) {
+        cur = table->table[i];
+	if (!xmlStrcmp(cur->name, name))
+	    return(cur);
+    }
+    return(NULL);
+}
+
+/**
+ * xmlGetDtdAttrDesc:
+ * @dtd:  a pointer to the DtD to search
+ * @elem:  the element name
+ * @name:  the attribute name
+ *
+ * Search the Dtd for the description of this attribute on
+ * this element.
+ *
+ * returns the xmlAttributePtr if found or NULL
+ */
+
+xmlAttributePtr
+xmlGetDtdAttrDesc(xmlDtdPtr dtd, const CHAR *elem, const CHAR *name) {
+    xmlAttributeTablePtr table;
+    xmlAttributePtr cur;
+    int i;
+
+    if (dtd == NULL) return(NULL);
+    if (dtd->attributes == NULL) return(NULL);
+    table = dtd->attributes;
+
+    for (i = 0;i < table->nb_attributes;i++) {
+        cur = table->table[i];
+	if ((!xmlStrcmp(cur->name, name)) &&
+	    (!xmlStrcmp(cur->elem, elem)))
+	    return(cur);
+    }
+    return(NULL);
+}
+
+/**
+ * xmlGetDtdNotationDesc:
+ * @dtd:  a pointer to the DtD to search
+ * @name:  the notation name
+ *
+ * Search the Dtd for the description of this notation
+ *
+ * returns the xmlNotationPtr if found or NULL
+ */
+
+xmlNotationPtr
+xmlGetDtdNotationDesc(xmlDtdPtr dtd, const CHAR *name) {
+    xmlNotationTablePtr table;
+    xmlNotationPtr cur;
+    int i;
+
+    if (dtd == NULL) return(NULL);
+    if (dtd->notations == NULL) return(NULL);
+    table = dtd->notations;
+
+    for (i = 0;i < table->nb_notations;i++) {
+        cur = table->table[i];
+	if (!xmlStrcmp(cur->name, name))
+	    return(cur);
+    }
+    return(NULL);
+}
+
+/**
+ * xmlIsMixedElement
+ * @doc:  the document
+ * @name:  the element name
+ *
+ * Search in the DtDs whether an element accept Mixed content (or ANY)
+ * basically if it is supposed to accept text childs
+ *
+ * returns 0 if no, 1 if yes, and -1 if no element description is available
+ */
+
+int
+xmlIsMixedElement(xmlDocPtr doc, const CHAR *name) {
+    xmlElementPtr elemDecl;
+
+    if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
+
+    elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
+    if ((elemDecl == NULL) && (doc->extSubset != NULL))
+	elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
+    if (elemDecl == NULL) return(-1);
+    switch (elemDecl->type) {
+	case XML_ELEMENT_TYPE_ELEMENT:
+	    return(0);
+        case XML_ELEMENT_TYPE_EMPTY:
+	    /*
+	     * return 1 for EMPTY since we want VC error to pop up
+	     * on <empty>     </empty> for example
+	     */
+	case XML_ELEMENT_TYPE_ANY:
+	case XML_ELEMENT_TYPE_MIXED:
+	    return(1);
+    }
+    return(1);
+}
+
+/**
+ * xmlValidateNameValue:
+ * @value:  an Name value
+ *
+ * Validate that the given value match Name production
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateNameValue(const CHAR *value) {
+    const CHAR *cur;
+
+    if (value == NULL) return(0);
+    cur = value;
+    
+    if (!IS_LETTER(*cur) && (*cur != '_') &&
+        (*cur != ':')) {
+	return(0);
+    }
+
+    while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
+           (*cur == '.') || (*cur == '-') ||
+	   (*cur == '_') || (*cur == ':') || 
+	   (IS_COMBINING(*cur)) ||
+	   (IS_EXTENDER(*cur)))
+	   cur++;
+
+    if (*cur != 0) return(0);
+
+    return(1);
+}
+
+/**
+ * xmlValidateNamesValue:
+ * @value:  an Names value
+ *
+ * Validate that the given value match Names production
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateNamesValue(const CHAR *value) {
+    const CHAR *cur;
+
+    if (value == NULL) return(0);
+    cur = value;
+    
+    if (!IS_LETTER(*cur) && (*cur != '_') &&
+        (*cur != ':')) {
+	return(0);
+    }
+
+    while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
+           (*cur == '.') || (*cur == '-') ||
+	   (*cur == '_') || (*cur == ':') || 
+	   (IS_COMBINING(*cur)) ||
+	   (IS_EXTENDER(*cur)))
+	   cur++;
+
+    while (IS_BLANK(*cur)) {
+	while (IS_BLANK(*cur)) cur++;
+
+	if (!IS_LETTER(*cur) && (*cur != '_') &&
+	    (*cur != ':')) {
+	    return(0);
+	}
+
+	while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
+	       (*cur == '.') || (*cur == '-') ||
+	       (*cur == '_') || (*cur == ':') || 
+	       (IS_COMBINING(*cur)) ||
+	       (IS_EXTENDER(*cur)))
+	       cur++;
+    }
+
+    if (*cur != 0) return(0);
+
+    return(1);
+}
+
+/**
+ * xmlValidateNmtokenValue:
+ * @value:  an Mntoken value
+ *
+ * Validate that the given value match Nmtoken production
+ *
+ * [ VC: Name Token ]
+ * 
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateNmtokenValue(const CHAR *value) {
+    const CHAR *cur;
+
+    if (value == NULL) return(0);
+    cur = value;
+    
+    if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
+        (*cur != '.') && (*cur != '-') &&
+        (*cur != '_') && (*cur != ':') && 
+        (!IS_COMBINING(*cur)) &&
+        (!IS_EXTENDER(*cur)))
+	return(0);
+
+    while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
+           (*cur == '.') || (*cur == '-') ||
+	   (*cur == '_') || (*cur == ':') || 
+	   (IS_COMBINING(*cur)) ||
+	   (IS_EXTENDER(*cur)))
+	   cur++;
+
+    if (*cur != 0) return(0);
+
+    return(1);
+    return(1);
+}
+
+/**
+ * xmlValidateNmtokensValue:
+ * @value:  an Mntokens value
+ *
+ * Validate that the given value match Nmtokens production
+ *
+ * [ VC: Name Token ]
+ * 
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateNmtokensValue(const CHAR *value) {
+    const CHAR *cur;
+
+    if (value == NULL) return(0);
+    cur = value;
+    
+    if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
+        (*cur != '.') && (*cur != '-') &&
+        (*cur != '_') && (*cur != ':') && 
+        (!IS_COMBINING(*cur)) &&
+        (!IS_EXTENDER(*cur)))
+	return(0);
+
+    while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
+           (*cur == '.') || (*cur == '-') ||
+	   (*cur == '_') || (*cur == ':') || 
+	   (IS_COMBINING(*cur)) ||
+	   (IS_EXTENDER(*cur)))
+	   cur++;
+
+    while (IS_BLANK(*cur)) {
+	while (IS_BLANK(*cur)) cur++;
+
+	if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
+	    (*cur != '.') && (*cur != '-') &&
+	    (*cur != '_') && (*cur != ':') && 
+	    (!IS_COMBINING(*cur)) &&
+	    (!IS_EXTENDER(*cur)))
+	    return(0);
+
+	while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
+	       (*cur == '.') || (*cur == '-') ||
+	       (*cur == '_') || (*cur == ':') || 
+	       (IS_COMBINING(*cur)) ||
+	       (IS_EXTENDER(*cur)))
+	       cur++;
+    }
+
+    if (*cur != 0) return(0);
+
+    return(1);
+}
+
+/**
+ * xmlValidateNotationDecl:
+ * @doc:  a document instance
+ * @nota:  a notation definition
+ *
+ * Try to validate a single notation definition
+ * basically it does the following checks as described by the
+ * XML-1.0 recommendation:
+ *  - it seems that no validity constraing exist on notation declarations
+ * But this function get called anyway ...
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
+                         xmlNotationPtr nota) {
+    int ret = 1;
+
+    return(ret);
+}
+
+/**
+ * xmlValidateAttributeValue:
+ * @type:  an attribute type
+ * @value:  an attribute value
+ *
+ * Validate that the given attribute value match  the proper production
+ *
+ * [ VC: ID ]
+ * Values of type ID must match the Name production....
+ *
+ * [ VC: IDREF ]
+ * Values of type IDREF must match the Name production, and values
+ * of type IDREFS must match Names ...
+ *
+ * [ VC: Entity Name ]
+ * Values of type ENTITY must match the Name production, values
+ * of type ENTITIES must match Names ...
+ *
+ * [ VC: Name Token ]
+ * Values of type NMTOKEN must match the Nmtoken production; values
+ * of type NMTOKENS must match Nmtokens. 
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateAttributeValue(xmlAttributeType type, const CHAR *value) {
+    switch (type) {
+	case XML_ATTRIBUTE_IDREFS:
+	case XML_ATTRIBUTE_ENTITIES:
+	    return(xmlValidateNamesValue(value));
+	case XML_ATTRIBUTE_IDREF:
+	case XML_ATTRIBUTE_ID:
+	case XML_ATTRIBUTE_ENTITY:
+	case XML_ATTRIBUTE_NOTATION:
+	    return(xmlValidateNameValue(value));
+	case XML_ATTRIBUTE_NMTOKENS:
+	case XML_ATTRIBUTE_ENUMERATION:
+	    return(xmlValidateNmtokensValue(value));
+	case XML_ATTRIBUTE_NMTOKEN:
+	    return(xmlValidateNmtokenValue(value));
+        case XML_ATTRIBUTE_CDATA:
+	    break;
+    }
+    return(1);
+}
+
+/**
+ * xmlValidateAttributeDecl:
+ * @doc:  a document instance
+ * @attr:  an attribute definition
+ *
+ * Try to validate a single attribute definition
+ * basically it does the following checks as described by the
+ * XML-1.0 recommendation:
+ *  - [ VC: Attribute Default Legal ]
+ *  - [ VC: Enumeration ]
+ *  - [ VC: ID Attribute Default ]
+ *
+ * The ID/IDREF uniqueness and matching are done separately
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
+                         xmlAttributePtr attr) {
+    int ret = 1;
+    int val;
+    CHECK_DTD;
+    if(attr == NULL) return(1);
+    
+    /* Attribute Default Legal */
+    /* Enumeration */
+    if (attr->defaultValue != NULL) {
+	val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
+	if (val == 0) {
+	    VERROR(ctxt->userData, 
+	       "Syntax of default value for attribute %s on %s is not valid\n",
+	           attr->name, attr->elem);
+	}
+        ret &= val;
+    }
+
+    /* ID Attribute Default */
+    if ((attr->type == XML_ATTRIBUTE_ID)&&
+        (attr->def != XML_ATTRIBUTE_IMPLIED) &&
+	(attr->def != XML_ATTRIBUTE_REQUIRED)) {
+	VERROR(ctxt->userData, 
+          "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
+	       attr->name, attr->elem);
+	ret = 0;
+    }
+
+    /* max ID per element */
+    if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
+        int nbId = 0;
+
+	/* the trick is taht we parse DtD as their own internal subset */
+        xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
+	                                          attr->elem);
+	if (elem != NULL) {
+	    nbId = xmlScanIDAttributeDecl(NULL, elem);
+	}
+	if (nbId >= 1)
+	    VERROR(ctxt->userData, 
+	   "Element %s has ID attribute defined in the external subset : %s\n",
+		   attr->elem, attr->name);
+    }
+
+    return(ret);
+}
+
+/**
+ * xmlValidateElementDecl:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ * @elem:  an element definition
+ *
+ * Try to validate a single element definition
+ * basically it does the following checks as described by the
+ * XML-1.0 recommendation:
+ *  - [ VC: One ID per Element Type ]
+ *  - [ VC: No Duplicate Types ]
+ *  - [ VC: Unique Element Type Declaration ]
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
+                       xmlElementPtr elem) {
+    int ret = 1;
+    xmlElementPtr tst;
+
+    CHECK_DTD;
+    
+    if (elem == NULL) return(1);
+
+    /* No Duplicate Types */
+    if (elem->type == XML_ELEMENT_TYPE_MIXED) {
+	xmlElementContentPtr cur, next;
+        const CHAR *name;
+
+	cur = elem->content;
+	while (cur != NULL) {
+	    if (cur->type != XML_ELEMENT_CONTENT_OR) break;
+	    if (cur->c1 == NULL) break;
+	    if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
+		name = cur->c1->name;
+		next = cur->c2;
+		while (next != NULL) {
+		    if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
+		        if (!xmlStrcmp(next->name, name)) {
+			    VERROR(ctxt->userData, 
+		   "Definition of %s has duplicate references of %s\n",
+				   elem->name, name);
+			    ret = 0;
+			}
+			break;
+		    }
+		    if (next->c1 == NULL) break;
+		    if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
+		    if (!xmlStrcmp(next->c1->name, name)) {
+			VERROR(ctxt->userData, 
+	       "Definition of %s has duplicate references of %s\n",
+			       elem->name, name);
+			ret = 0;
+		    }
+		    next = next->c2;
+		}
+	    }
+	    cur = cur->c2;
+	}
+    }
+
+    /* VC: Unique Element Type Declaration */
+    tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
+    if ((tst != NULL ) && (tst != elem)) {
+	VERROR(ctxt->userData, "Redefinition of element %s\n",
+	       elem->name);
+	ret = 0;
+    }
+    tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
+    if ((tst != NULL ) && (tst != elem)) {
+	VERROR(ctxt->userData, "Redefinition of element %s\n",
+	       elem->name);
+	ret = 0;
+    }
+
+    /* One ID per Element Type */
+    if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
+	ret = 0;
+    }
+    return(ret);
+}
+
+/**
+ * xmlValidateOneAttribute:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ * @elem:  an element instance
+ * @attr:  an attribute instance
+ *
+ * Try to validate a single attribute for an element
+ * basically it * does the following checks as described by the
+ * XML-1.0 recommendation:
+ *  - [ VC: Attribute Value Type ]
+ *  - [ VC: Fixed Attribute Default ]
+ *  - [ VC: Entity Name ]
+ *  - [ VC: Name Token ]
+ *  - [ VC: ID ]
+ *  - [ VC: IDREF ]
+ *  - [ VC: Entity Name ]
+ *  - [ VC: Notation Attributes ]
+ *
+ * The ID/IDREF uniqueness and matching are done separately
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
+                        xmlNodePtr elem, xmlAttrPtr attr, const CHAR *value) {
+    xmlElementPtr elemDecl;
+    xmlAttributePtr attrDecl;
+    int val;
+    int ret = 1;
+
+    CHECK_DTD;
+    if ((elem == NULL) || (elem->name == NULL)) return(0);
+    if ((attr == NULL) || (attr->name == NULL)) return(0);
+
+    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
+    if ((attrDecl == NULL) && (doc->extSubset != NULL))
+	attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
+
+
+    /* Validity Constraint: Attribute Value Type */
+    if (attrDecl == NULL) {
+	VERROR(ctxt->userData,
+	       "No declaration for attribute %s on element %s\n",
+	       attr->name, elem->name);
+	return(0);
+    }
+    val = xmlValidateAttributeValue(attrDecl->type, value);
+    if (val == 0) {
+	VERROR(ctxt->userData, 
+	   "Syntax of value for attribute %s on %s is not valid\n",
+	       attr->name, elem->name);
+        ret = 0;
+    }
+
+    /* Validity Constraint: Notation Attributes */
+    if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
+        xmlEnumerationPtr tree = attrDecl->tree;
+        xmlNotationPtr nota;
+
+        /* First check that the given NOTATION was declared */
+	nota = xmlGetDtdNotationDesc(doc->intSubset, value);
+	if (nota == NULL)
+	    nota = xmlGetDtdNotationDesc(doc->extSubset, value);
+	
+	if (nota == NULL) {
+	    VERROR(ctxt->userData, 
+       "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
+		   value, attr->name, elem->name);
+	    ret = 0;
+        }
+
+	/* Second, verify that it's among the list */
+	while (tree != NULL) {
+	    if (!xmlStrcmp(tree->name, value)) break;
+	    tree = tree->next;
+	}
+	if (tree == NULL) {
+	    VERROR(ctxt->userData, 
+   "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
+		   value, attr->name, elem->name);
+	    ret = 0;
+	}
+    }
+
+    /* Validity Constraint: Enumeration */
+    if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
+        xmlEnumerationPtr tree = attrDecl->tree;
+	while (tree != NULL) {
+	    if (!xmlStrcmp(tree->name, value)) break;
+	    tree = tree->next;
+	}
+	if (tree == NULL) {
+	    VERROR(ctxt->userData, 
+       "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
+		   value, attr->name, elem->name);
+	    ret = 0;
+	}
+    }
+
+    /* Fixed Attribute Default */
+    if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
+        (xmlStrcmp(attrDecl->defaultValue, value))) {
+	VERROR(ctxt->userData, 
+	   "Value for attribute %s on %s must be \"%s\"\n",
+	       attr->name, elem->name, attrDecl->defaultValue);
+        ret = 0;
+    }
+
+    elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
+    if ((elemDecl == NULL) && (doc->extSubset != NULL))
+	elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
+    if (elemDecl == NULL) {
+	/* the error has or will be reported soon in xmlValidateOneElement */
+	return(0);
+    }
+    return(ret);
+}
+
+int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
+				  xmlElementContentPtr cont);
+
+/**
+ * xmlValidateElementTypeExpr:
+ * @ctxt:  the validation context
+ * @child:  pointer to the child list
+ * @cont:  pointer to the content declaration
+ *
+ * Try to validate the content of an element of type element
+ * but don't handle the occurence factor
+ *
+ * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
+ *         also update child value in-situ.
+ */
+
+int
+xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
+			   xmlElementContentPtr cont) {
+    xmlNodePtr cur;
+    int ret = 1;
+
+    if (cont == NULL) return(-1);
+    while (*child != NULL) {
+        if ((*child)->type == XML_PI_NODE) {
+	    *child = (*child)->next;
+	    continue;
+	}
+        if ((*child)->type == XML_COMMENT_NODE) {
+	    *child = (*child)->next;
+	    continue;
+	}
+	else if ((*child)->type != XML_ELEMENT_NODE) {
+	    return(-1);
+	}
+	break;
+    }
+    switch (cont->type) {
+	case XML_ELEMENT_CONTENT_PCDATA:
+	    /* Internal error !!! */
+	    fprintf(stderr, "Internal: MIXED struct bad\n");
+	    return(-1);
+	case XML_ELEMENT_CONTENT_ELEMENT:
+	    if (*child == NULL) return(0);
+	    ret = (!xmlStrcmp((*child)->name, cont->name));
+	    if (ret == 1)
+	        *child = (*child)->next;
+	    return(ret);
+	case XML_ELEMENT_CONTENT_OR:
+	    cur = *child;
+	    ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
+	    if (ret == -1) return(-1);
+	    if (ret == 1) {
+		 return(1);
+	    }
+	    /* rollback and retry the other path */
+	    *child = cur;
+	    ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
+	    if (ret == -1) return(-1);
+	    if (ret == 0) {
+		*child = cur;
+		return(0);
+	    }
+	    return(1);
+	case XML_ELEMENT_CONTENT_SEQ:
+	    cur = *child;
+	    ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
+	    if (ret == -1) return(-1);
+	    if (ret == 0) {
+		*child = cur;
+		return(0);
+	    }
+	    ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
+	    if (ret == -1) return(-1);
+	    if (ret == 0) {
+		*child = cur;
+		return(0);
+	    }
+	    return(1);
+    }
+    return(ret);
+}
+
+/**
+ * xmlValidateElementTypeElement:
+ * @ctxt:  the validation context
+ * @child:  pointer to the child list
+ * @cont:  pointer to the content declaration
+ *
+ * Try to validate the content of an element of type element
+ * yeah, Yet Another Regexp Implementation, and recursive
+ *
+ * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
+ *         also update child and content values in-situ.
+ */
+
+int
+xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
+			      xmlElementContentPtr cont) {
+    xmlNodePtr cur;
+    int ret = 1;
+
+    if (cont == NULL) return(-1);
+    while (*child != NULL) {
+        if ((*child)->type == XML_PI_NODE) {
+	    *child = (*child)->next;
+	    continue;
+	}
+        if ((*child)->type == XML_COMMENT_NODE) {
+	    *child = (*child)->next;
+	    continue;
+	}
+	else if ((*child)->type != XML_ELEMENT_NODE) {
+	    return(-1);
+	}
+	break;
+    }
+    cur = *child;
+    ret = xmlValidateElementTypeExpr(ctxt, child, cont);
+    if (ret == -1) return(-1);
+    switch (cont->ocur) {
+	case XML_ELEMENT_CONTENT_ONCE:
+	    if (ret == 1) {
+		return(1);
+	    }
+	    *child = cur;
+	    return(0);
+	case XML_ELEMENT_CONTENT_OPT:
+	    if (ret == 0) {
+		*child = cur;
+	        return(1);
+	    }
+	    break;
+	case XML_ELEMENT_CONTENT_MULT:
+	    if (ret == 0) {
+		*child = cur;
+	        break;
+	    }
+	    /* no break on purpose */
+	case XML_ELEMENT_CONTENT_PLUS:
+	    if (ret == 0) {
+		*child = cur;
+	        return(0);
+	    }
+	    do {
+		cur = *child;
+		ret = xmlValidateElementTypeExpr(ctxt, child, cont);
+	    } while (ret == 1);
+	    if (ret == -1) return(-1);
+	    *child = cur;
+	    break;
+    }
+    while (*child != NULL) {
+        if ((*child)->type == XML_PI_NODE) {
+	    *child = (*child)->next;
+	    continue;
+	}
+        if ((*child)->type == XML_COMMENT_NODE) {
+	    *child = (*child)->next;
+	    continue;
+	}
+	else if ((*child)->type != XML_ELEMENT_NODE) {
+	    return(-1);
+	}
+	break;
+    }
+    return(1);
+}
+
+/**
+ * xmlSprintfElementChilds:
+ * @buf:  an output buffer
+ * @content:  An element
+ * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
+ *
+ * This will dump the list of childs to the buffer
+ * Intended just for the debug routine
+ */
+void
+xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
+    xmlNodePtr cur;
+
+    if (node == NULL) return;
+    if (glob) strcat(buf, "(");
+    cur = node->childs;
+    while (cur != NULL) {
+        switch (cur->type) {
+            case XML_ELEMENT_NODE:
+	         strcat(buf, cur->name);
+		 if (cur->next != NULL)
+		     strcat(buf, " ");
+		 break;
+            case XML_TEXT_NODE:
+            case XML_CDATA_SECTION_NODE:
+            case XML_ENTITY_REF_NODE:
+	         strcat(buf, "CDATA");
+		 if (cur->next != NULL)
+		     strcat(buf, " ");
+		 break;
+            case XML_ATTRIBUTE_NODE:
+            case XML_DOCUMENT_NODE:
+            case XML_DOCUMENT_TYPE_NODE:
+            case XML_DOCUMENT_FRAG_NODE:
+            case XML_NOTATION_NODE:
+	         strcat(buf, "???");
+		 if (cur->next != NULL)
+		     strcat(buf, " ");
+		 break;
+            case XML_ENTITY_NODE:
+            case XML_PI_NODE:
+            case XML_COMMENT_NODE:
+		 break;
+	}
+	cur = cur->next;
+    }
+    if (glob) strcat(buf, ")");
+}
+
+
+/**
+ * xmlValidateOneElement:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ * @elem:  an element instance
+ *
+ * Try to validate a single element and it's attributes,
+ * basically it does the following checks as described by the
+ * XML-1.0 recommendation:
+ *  - [ VC: Element Valid ]
+ *  - [ VC: Required Attribute ]
+ * Then call xmlValidateOneAttribute() for each attribute present.
+ *
+ * The ID/IDREF checkings are done separately
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
+                      xmlNodePtr elem) {
+    xmlElementPtr elemDecl;
+    xmlElementContentPtr cont;
+    xmlNodePtr child;
+    int ret = 1;
+    const CHAR *name;
+
+    CHECK_DTD;
+
+    if ((elem == NULL) || (elem->name == NULL)) return(0);
+
+    elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
+    if ((elemDecl == NULL) && (doc->extSubset != NULL))
+	elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
+    if (elemDecl == NULL) {
+	VERROR(ctxt->userData, "No declaration for element %s\n",
+	       elem->name);
+	return(0);
+    }
+
+    /* Check taht the element content matches the definition */
+    switch (elemDecl->type) {
+        case XML_ELEMENT_TYPE_EMPTY:
+	    if (elem->childs != NULL) {
+		VERROR(ctxt->userData,
+	       "Element %s was declared EMPTY this one has content\n",
+	               elem->name);
+		ret = 0;
+	    }
+	    break;
+        case XML_ELEMENT_TYPE_ANY:
+	    /* I don't think anything is required then */
+	    break;
+        case XML_ELEMENT_TYPE_MIXED:
+	    /* Hum, this start to get messy */
+	    child = elem->childs;
+	    while (child != NULL) {
+	        if (child->type == XML_ELEMENT_NODE) {
+		    name = child->name;
+		    cont = elemDecl->content;
+		    while (cont != NULL) {
+		        if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
+			    if (!xmlStrcmp(cont->name, name)) break;
+			} else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
+			   (cont->c1 != NULL) &&
+			   (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
+			    if (!xmlStrcmp(cont->c1->name, name)) break;
+			} else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
+			    (cont->c1 == NULL) ||
+			    (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
+			    /* Internal error !!! */
+			    fprintf(stderr, "Internal: MIXED struct bad\n");
+			    break;
+			}
+			cont = cont->c2;
+		    }
+		    if (cont == NULL) {
+			VERROR(ctxt->userData,
+	       "Element %s is not declared in %s list of possible childs\n",
+			       name, elem->name);
+			ret = 0;
+		    }
+		}
+	        child = child->next;
+	    }
+	    break;
+        case XML_ELEMENT_TYPE_ELEMENT:
+	    child = elem->childs;
+	    cont = elemDecl->content;
+	    ret = xmlValidateElementTypeElement(ctxt, &child, cont);
+	    if ((ret == 0) || (child != NULL)) {
+	        char expr[1000];
+	        char list[2000];
+
+		expr[0] = 0;
+		xmlSprintfElementContent(expr, cont, 1);
+		list[0] = 0;
+		xmlSprintfElementChilds(list, elem, 1);
+
+		VERROR(ctxt->userData,
+	   "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
+	               elem->name, expr, list);
+		ret = 0;
+	    }
+	    break;
+    }
+
+    return(ret);
+}
+
+/**
+ * xmlValidateRoot:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ *
+ * Try to validate a the root element
+ * basically it does the following check as described by the
+ * XML-1.0 recommendation:
+ *  - [ VC: Root Element Type ]
+ * it doesn't try to recurse or apply other check to the element
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
+    if (doc == NULL) return(0);
+
+    if ((doc->intSubset == NULL) ||
+	(doc->intSubset->name == NULL)) {
+	VERROR(ctxt->userData, "Not valid: no DtD found\n");
+        return(0);
+    }
+    if ((doc->root == NULL) || (doc->root->name == NULL)) {
+	VERROR(ctxt->userData, "Not valid: no root element\n");
+        return(0);
+    }
+    if (xmlStrcmp(doc->intSubset->name, doc->root->name)) {
+	VERROR(ctxt->userData,
+	       "Not valid: root and DtD name do not match %s and %s\n",
+	       doc->root->name, doc->intSubset->name);
+	return(0);
+    }
+    return(1);
+}
+
+
+/**
+ * xmlValidateElement:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ * @elem:  an element instance
+ *
+ * Try to validate the subtree under an element 
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
+    CHECK_DTD;
+
+    return(1);
+}
+
+/**
+ * xmlValidateDtd:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ * @dtd:  a dtd instance
+ *
+ * Try to validate the dtd instance
+ *
+ * basically it does check all the definitions in the DtD.
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
+    return(1);
+}
+
+/**
+ * xmlValidateDocument:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ *
+ * Try to validate the document instance
+ *
+ * basically it does the all the checks described by the
+ * i.e. validates the internal and external subset (if present)
+ * and validate the document tree.
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
+    if (!xmlValidateRoot(ctxt, doc)) return(0);
+
+    return(1);
+}
+