more testing on the Relax-NG front, cleaning up the regression tests

* check-relaxng-test-suite.py relaxng.c: more testing on the
  Relax-NG front, cleaning up the regression tests failures
  current state and I forgot support for "mixed":
  found 373 test schemas: 280 success 93 failures
  found 529 test instances: 401 success 68 failures
* tree.c include/libxml/tree.h xmlschemastypes.c: finished and
  moved the Name, NCName and QName validation routine in tree.c
* uri.c: fixed handling of URI ending up with #, i.e. having
  an empty fragment ID.
* result/relaxng/*: updated the results
Daniel
diff --git a/relaxng.c b/relaxng.c
index 08b82d0..229c816 100644
--- a/relaxng.c
+++ b/relaxng.c
@@ -350,6 +350,7 @@
  ************************************************************************/
 static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
 static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
+static void xmlRelaxNGNormExtSpace(xmlChar *value);
 
 /**
  * xmlRelaxNGFreeDocument:
@@ -954,11 +955,13 @@
 	    } else {
 		int found = 0;
 
+		xmlRelaxNGNormExtSpace(name);
 		tmp = root->children;
 		while (tmp != NULL) {
 		    tmp2 = tmp->next;
 		    if (IS_RELAXNG(tmp, "define")) {
 			name2 = xmlGetProp(tmp, BAD_CAST "name");
+			xmlRelaxNGNormExtSpace(name2);
 			if (name2 != NULL) {
 			    if (xmlStrEqual(name, name2)) {
 				found = 1;
@@ -1193,6 +1196,7 @@
     if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2))			\
         if (ctxt->error != NULL) ctxt->error(ctxt->userData, a, b, c)
 
+#ifdef DEBUG
 static const char *
 xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
     if (def == NULL)
@@ -1221,6 +1225,8 @@
     }
     return("unknown");
 }
+#endif
+
 #if 0
 /**
  * xmlRelaxNGErrorContext:
@@ -1652,6 +1658,10 @@
     if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
 	ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
 	if (ret != NULL) {
+	    if (ret[0] == 0) {
+		xmlFree(ret);
+		return(NULL);
+	    }
 	    escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
 	    if (escape == NULL) {
 		return(ret);
@@ -1664,6 +1674,10 @@
     while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
 	ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
 	if (ret != NULL) {
+	    if (ret[0] == 0) {
+		xmlFree(ret);
+		return(NULL);
+	    }
 	    escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
 	    if (escape == NULL) {
 		return(ret);
@@ -1700,6 +1714,14 @@
 
     type = xmlGetProp(node, BAD_CAST "type");
     if (type != NULL) {
+	xmlRelaxNGNormExtSpace(type);
+	if (xmlValidateNCName(type, 0)) {
+	    if (ctxt->error != NULL)
+		ctxt->error(ctxt->userData,
+		    "value type '%s' is not an NCName\n",
+			    type);
+	    ctxt->nbErrors++;
+	}
 	library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
 	if (library == NULL)
 	    library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
@@ -1786,6 +1808,14 @@
 	ctxt->nbErrors++;
 	return(NULL);
     }
+    xmlRelaxNGNormExtSpace(type);
+    if (xmlValidateNCName(type, 0)) {
+	if (ctxt->error != NULL)
+	    ctxt->error(ctxt->userData,
+		"data type '%s' is not an NCName\n",
+			type);
+	ctxt->nbErrors++;
+    }
     library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
     if (library == NULL)
 	library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
@@ -2119,6 +2149,11 @@
 	}
     }
     child = node->children;
+    if (child == NULL) {
+	if (ctxt->error != NULL)
+	    ctxt->error(ctxt->userData, "Element interleave is empty\n");
+	ctxt->nbErrors++;
+    }
     while (child != NULL) {
 	if (IS_RELAXNG(child, "element")) {
 	    cur = xmlRelaxNGParseElement(ctxt, child);
@@ -2218,6 +2253,14 @@
 			"define has no name\n");
 	ctxt->nbErrors++;
     } else {
+	xmlRelaxNGNormExtSpace(name);
+	if (xmlValidateNCName(name, 0)) {
+	    if (ctxt->error != NULL)
+		ctxt->error(ctxt->userData,
+		    "define name '%s' is not an NCName\n",
+			    name);
+	    ctxt->nbErrors++;
+	}
 	def = xmlRelaxNGNewDefine(ctxt, node);
 	if (def == NULL) {
 	    xmlFree(name);
@@ -2282,6 +2325,9 @@
 xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
     xmlRelaxNGDefinePtr def = NULL;
 
+    if (node == NULL) {
+	return(NULL);
+    }
     if (IS_RELAXNG(node, "element")) {
 	def = xmlRelaxNGParseElement(ctxt, node);
     } else if (IS_RELAXNG(node, "attribute")) {
@@ -2291,6 +2337,11 @@
 	if (def == NULL)
 	    return(NULL);
 	def->type = XML_RELAXNG_EMPTY;
+	if (node->children != NULL) {
+	    if (ctxt->error != NULL)
+		ctxt->error(ctxt->userData, "empty: had a child node\n");
+	    ctxt->nbErrors++;
+	}
     } else if (IS_RELAXNG(node, "text")) {
 	def = xmlRelaxNGNewDefine(ctxt, node);
 	if (def == NULL)
@@ -2306,31 +2357,66 @@
 	if (def == NULL)
 	    return(NULL);
 	def->type = XML_RELAXNG_ZEROORMORE;
-	def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
+	if (node->children == NULL) {
+	    if (ctxt->error != NULL)
+		ctxt->error(ctxt->userData,
+			    "Element %s is empty\n", node->name);
+	    ctxt->nbErrors++;
+	} else {
+	    def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
+	} 
     } else if (IS_RELAXNG(node, "oneOrMore")) {
 	def = xmlRelaxNGNewDefine(ctxt, node);
 	if (def == NULL)
 	    return(NULL);
 	def->type = XML_RELAXNG_ONEORMORE;
-	def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
+	if (node->children == NULL) {
+	    if (ctxt->error != NULL)
+		ctxt->error(ctxt->userData,
+			    "Element %s is empty\n", node->name);
+	    ctxt->nbErrors++;
+	} else {
+	    def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
+	} 
     } else if (IS_RELAXNG(node, "optional")) {
 	def = xmlRelaxNGNewDefine(ctxt, node);
 	if (def == NULL)
 	    return(NULL);
 	def->type = XML_RELAXNG_OPTIONAL;
-	def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
+	if (node->children == NULL) {
+	    if (ctxt->error != NULL)
+		ctxt->error(ctxt->userData,
+			    "Element %s is empty\n", node->name);
+	    ctxt->nbErrors++;
+	} else {
+	    def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
+	} 
     } else if (IS_RELAXNG(node, "choice")) {
 	def = xmlRelaxNGNewDefine(ctxt, node);
 	if (def == NULL)
 	    return(NULL);
 	def->type = XML_RELAXNG_CHOICE;
-	def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
+	if (node->children == NULL) {
+	    if (ctxt->error != NULL)
+		ctxt->error(ctxt->userData,
+			    "Element %s is empty\n", node->name);
+	    ctxt->nbErrors++;
+	} else {
+	    def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
+	} 
     } else if (IS_RELAXNG(node, "group")) {
 	def = xmlRelaxNGNewDefine(ctxt, node);
 	if (def == NULL)
 	    return(NULL);
 	def->type = XML_RELAXNG_GROUP;
-	def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
+	if (node->children == NULL) {
+	    if (ctxt->error != NULL)
+		ctxt->error(ctxt->userData,
+			    "Element %s is empty\n", node->name);
+	    ctxt->nbErrors++;
+	} else {
+	    def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
+	} 
     } else if (IS_RELAXNG(node, "ref")) {
 	def = xmlRelaxNGNewDefine(ctxt, node);
 	if (def == NULL)
@@ -2343,6 +2429,14 @@
 			    "ref has no name\n");
 	    ctxt->nbErrors++;
 	} else {
+	    xmlRelaxNGNormExtSpace(def->name);
+	    if (xmlValidateNCName(def->name, 0)) {
+		if (ctxt->error != NULL)
+		    ctxt->error(ctxt->userData,
+			"ref name '%s' is not an NCName\n",
+				def->name);
+		ctxt->nbErrors++;
+	    }
 	    if ((ctxt->define != NULL) &&
 	        (xmlStrEqual(ctxt->define, def->name))) {
 		if (ctxt->error != NULL)
@@ -2390,9 +2484,11 @@
 	}
     } else if (IS_RELAXNG(node, "data")) {
 	def = xmlRelaxNGParseData(ctxt, node);
+#if 0
     } else if (IS_RELAXNG(node, "define")) {
 	xmlRelaxNGParseDefine(ctxt, node);
 	def = NULL;
+#endif
     } else if (IS_RELAXNG(node, "value")) {
 	def = xmlRelaxNGParseValue(ctxt, node);
     } else if (IS_RELAXNG(node, "list")) {
@@ -2400,7 +2496,14 @@
 	if (def == NULL)
 	    return(NULL);
 	def->type = XML_RELAXNG_LIST;
-	def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
+	if (node->children == NULL) {
+	    if (ctxt->error != NULL)
+		ctxt->error(ctxt->userData,
+			    "Element %s is empty\n", node->name);
+	    ctxt->nbErrors++;
+	} else {
+	    def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
+	} 
     } else if (IS_RELAXNG(node, "interleave")) {
 	def = xmlRelaxNGParseInterleave(ctxt, node);
     } else if (IS_RELAXNG(node, "externalRef")) {
@@ -2486,6 +2589,15 @@
 		ctxt->error(ctxt->userData,
 			    "parentRef has no name\n");
 	    ctxt->nbErrors++;
+	} else {
+	    xmlRelaxNGNormExtSpace(def->name);
+	    if (xmlValidateNCName(def->name, 0)) {
+		if (ctxt->error != NULL)
+		    ctxt->error(ctxt->userData,
+			"parentRef name '%s' is not an NCName\n",
+				def->name);
+		ctxt->nbErrors++;
+	    }
 	}
 	if (node->children != NULL) {
 	    if (ctxt->error != NULL)
@@ -2501,7 +2613,7 @@
 			    "Could not create references hash\n");
 	    ctxt->nbErrors++;
 	    def = NULL;
-	} else {
+	} else if (def->name != NULL) {
 	    int tmp;
 
 	    tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
@@ -2523,9 +2635,15 @@
 		}
 	    }
 	}
-    } else {
+    } else if (IS_RELAXNG(node, "mixed")) {
 	TODO
 	ctxt->nbErrors++;
+    } else {
+	if (ctxt->error != NULL)
+	    ctxt->error(ctxt->userData,
+		"Unexpected node %s is not a pattern\n",
+			node->name);
+	ctxt->nbErrors++;
 	def = NULL;
     }
     return(def);
@@ -2542,7 +2660,7 @@
  */
 static xmlRelaxNGDefinePtr
 xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
-    xmlRelaxNGDefinePtr ret, cur, last;
+    xmlRelaxNGDefinePtr ret, cur;
     xmlNodePtr child;
     int old_flags;
 
@@ -2565,11 +2683,9 @@
     if (cur != NULL)
 	child = child->next;
 
-    last = NULL;
-    while (child != NULL) {
+    if (child != NULL) {
 	cur = xmlRelaxNGParsePattern(ctxt, child);
 	if (cur != NULL) {
-	    cur->parent = ret;
 	    switch (cur->type) {
 		case XML_RELAXNG_EMPTY:
 		case XML_RELAXNG_NOT_ALLOWED:
@@ -2588,37 +2704,31 @@
 		case XML_RELAXNG_CHOICE:
 		case XML_RELAXNG_GROUP:
 		case XML_RELAXNG_INTERLEAVE:
-		    if (last == NULL) {
-			ret->content = last = cur;
-		    } else {
-			if ((last->type == XML_RELAXNG_ELEMENT) &&
-			    (ret->content == last)) {
-			    ret->content = xmlRelaxNGNewDefine(ctxt, node);
-			    if (ret->content != NULL) {
-				ret->content->type = XML_RELAXNG_GROUP;
-				ret->content->content = last;
-			    } else {
-				ret->content = last;
-			    }
-			}
-			last->next = cur;
-			last = cur;
-		    }
+		    ret->content = cur;
 		    cur->parent = ret;
 		    break;
 		case XML_RELAXNG_ATTRIBUTE:
-		    cur->next = ret->attrs;
-		    ret->attrs = cur;
+		    if (ctxt->error != NULL)
+			ctxt->error(ctxt->userData,
+		"attribute has an attribute child\n");
+		    ctxt->nbErrors++;
 		    break;
 		case XML_RELAXNG_START:
 		case XML_RELAXNG_EXCEPT:
-		    TODO
+		    if (ctxt->error != NULL)
+			ctxt->error(ctxt->userData,
+		"attribute has invalid content\n");
 		    ctxt->nbErrors++;
 		    break;
 	    }
 	}
 	child = child->next;
     }
+    if (child != NULL) {
+	if (ctxt->error != NULL)
+	    ctxt->error(ctxt->userData, "attribute has multiple children\n");
+	ctxt->nbErrors++;
+    }
     ctxt->flags = old_flags;
     return(ret);
 }
@@ -2639,8 +2749,19 @@
     xmlRelaxNGDefinePtr ret, cur, last = NULL;
     xmlNodePtr child;
 
-    if (!IS_RELAXNG(node, "except"))
+    if (!IS_RELAXNG(node, "except")) {
+	if (ctxt->error != NULL)
+	    ctxt->error(ctxt->userData,
+		"Expecting an except node\n");
+	ctxt->nbErrors++;
 	return(NULL);
+    }
+    if (node->next != NULL) {
+	if (ctxt->error != NULL)
+	    ctxt->error(ctxt->userData,
+		"exceptNameClass allows only a single except node\n");
+	ctxt->nbErrors++;
+    }
     if (node->children == NULL) {
 	if (ctxt->error != NULL)
 	    ctxt->error(ctxt->userData,
@@ -2695,6 +2816,20 @@
 
     if (IS_RELAXNG(node, "name")) {
 	val = xmlNodeGetContent(node);
+	xmlRelaxNGNormExtSpace(val);
+	if (xmlValidateNCName(val, 0)) {
+	    if (ctxt->error != NULL) {
+		if (node->parent != NULL)
+		    ctxt->error(ctxt->userData,
+			"Element %s name '%s' is not an NCName\n",
+				node->parent->name, val);
+		else
+		    ctxt->error(ctxt->userData,
+			"name '%s' is not an NCName\n",
+				val);
+	    }
+	    ctxt->nbErrors++;
+	}
 	ret->name = val;
 	val = xmlGetProp(node, BAD_CAST "ns");
 	ret->ns = val;
@@ -2721,8 +2856,30 @@
 			       (def->type == XML_RELAXNG_ATTRIBUTE));
 	}
     } else if (IS_RELAXNG(node, "choice")) {
-	TODO
-	ctxt->nbErrors++;
+	if (node->children == NULL) {
+	    if (ctxt->error != NULL)
+		ctxt->error(ctxt->userData,
+		    "Element choice is empty\n");
+	    ctxt->nbErrors++;
+	} else {
+	    xmlNodePtr child;
+	    xmlRelaxNGDefinePtr last = NULL, tmp;
+
+	    child = node->children;
+	    while (child != NULL) {
+		tmp = xmlRelaxNGParseExceptNameClass(ctxt, child,
+				   (def->type == XML_RELAXNG_ATTRIBUTE));
+		if (tmp != NULL) {
+		    if (last == NULL) {
+			last = ret->nameClass = tmp;
+		    } else {
+			last->next = tmp;
+			last = tmp;
+		    }
+		}
+		child = child->next;
+	    }
+	}
     } else {
 	if (ctxt->error != NULL)
 	    ctxt->error(ctxt->userData,
@@ -2894,18 +3051,47 @@
     int ret = 0;
     xmlRelaxNGDefinePtr def = NULL;
 
-    while (nodes != NULL) {
-	if (IS_RELAXNG(nodes, "empty")) {
-	    TODO
+    if (nodes == NULL) {
+	if (ctxt->error != NULL)
+	    ctxt->error(ctxt->userData,
+			"start has no children\n");
+	ctxt->nbErrors++;
+	return(-1);
+    }
+    if (IS_RELAXNG(nodes, "empty")) {
+	def = xmlRelaxNGNewDefine(ctxt, nodes);
+	if (def == NULL)
+	    return(-1);
+	def->type = XML_RELAXNG_EMPTY;
+	if (nodes->children != NULL) {
+	    if (ctxt->error != NULL)
+		ctxt->error(ctxt->userData, "element empty is not empty\n");
 	    ctxt->nbErrors++;
-	} else if (IS_RELAXNG(nodes, "notAllowed")) {
-	    TODO
-	    ctxt->nbErrors++;
-	} else {
-	    def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
-	    ctxt->grammar->start = def;
 	}
-	nodes = nodes->next;
+	ctxt->grammar->start = def;
+    } else if (IS_RELAXNG(nodes, "notAllowed")) {
+	def = xmlRelaxNGNewDefine(ctxt, nodes);
+	if (def == NULL)
+	    return(-1);
+	def->type = XML_RELAXNG_NOT_ALLOWED;
+	if (nodes->children != NULL) {
+	    if (ctxt->error != NULL)
+		ctxt->error(ctxt->userData,
+			"element notAllowed is not empty\n");
+	    ctxt->nbErrors++;
+	}
+	ctxt->grammar->start = def;
+    } else {
+	def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
+	ctxt->grammar->start = def;
+    }
+    nodes = nodes->next;
+    if (nodes != NULL) {
+	if (ctxt->error != NULL)
+	    ctxt->error(ctxt->userData,
+			"start more than one children\n");
+	ctxt->nbErrors++;
+	return(-1);
     }
     return(ret);
 }
@@ -2936,7 +3122,7 @@
 	    if (nodes->children == NULL) {
 		if (ctxt->error != NULL)
 		    ctxt->error(ctxt->userData,
-				"grammar has no children\n");
+				"start has no children\n");
 		ctxt->nbErrors++;
 	    } else {
 		tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
@@ -3455,6 +3641,153 @@
 }
 
 /**
+ * xmlRelaxNGNormExtSpace:
+ * @value:  a value
+ *
+ * Removes the leading and ending spaces of the value
+ * The string is modified "in situ"
+ */
+static void
+xmlRelaxNGNormExtSpace(xmlChar *value) {
+    xmlChar *start = value;
+    xmlChar *cur = value;
+    if (value == NULL)
+	return;
+
+    while (IS_BLANK(*cur)) cur++;
+    if (cur == start) {
+	do {
+	    while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
+	    if (*cur == 0)
+		return;
+	    start = cur;
+	    while (IS_BLANK(*cur)) cur++;
+	    if (*cur == 0) {
+		*start = 0;
+	        return;
+	    }
+	} while (1);
+    } else {
+	do {
+	    while ((*cur != 0) && (!IS_BLANK(*cur))) 
+		*start++ = *cur++;
+	    if (*cur == 0) {
+		*start = 0;
+		return;
+	    }
+	    /* don't try to normalize the inner spaces */
+	    while (IS_BLANK(*cur)) cur++;
+		*start++ = *cur++;
+	    if (*cur == 0) {
+		*start = 0;
+	        return;
+	    }
+	} while (1);
+    }
+}
+
+/**
+ * xmlRelaxNGCheckAttributes:
+ * @ctxt:  a Relax-NG parser context
+ * @node:  a Relax-NG node
+ *
+ * Check all the attributes on the given node
+ */
+static void
+xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
+    xmlAttrPtr cur, next;
+
+    cur = node->properties;
+    while (cur != NULL) {
+	next = cur->next;
+	if ((cur->ns == NULL) ||
+	    (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
+	    if (xmlStrEqual(cur->name, BAD_CAST "name")) {
+		if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
+		    (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
+		    (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
+		    (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
+		    (!xmlStrEqual(node->name, BAD_CAST "define"))) {
+		    if (ctxt->error != NULL)
+			ctxt->error(ctxt->userData,
+				"Attribute %s is not allowed on %s\n",
+				    cur->name, node->name);
+		    ctxt->nbErrors++;
+		}
+	    } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
+		if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
+		    (!xmlStrEqual(node->name, BAD_CAST "data"))) {
+		    if (ctxt->error != NULL)
+			ctxt->error(ctxt->userData,
+				"Attribute %s is not allowed on %s\n",
+				    cur->name, node->name);
+		    ctxt->nbErrors++;
+		}
+	    } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
+		if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
+		    (!xmlStrEqual(node->name, BAD_CAST "include"))) {
+		    if (ctxt->error != NULL)
+			ctxt->error(ctxt->userData,
+				"Attribute %s is not allowed on %s\n",
+				    cur->name, node->name);
+		    ctxt->nbErrors++;
+		}
+	    } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
+		if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
+		    (!xmlStrEqual(node->name, BAD_CAST "define"))) {
+		    if (ctxt->error != NULL)
+			ctxt->error(ctxt->userData,
+				"Attribute %s is not allowed on %s\n",
+				    cur->name, node->name);
+		    ctxt->nbErrors++;
+		}
+	    } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
+		xmlChar *val;
+		xmlURIPtr uri;
+
+		val = xmlNodeListGetString(node->doc, cur->children, 1);
+		if (val != NULL) {
+		    if (val[0] != 0) {
+			uri = xmlParseURI((const char *) val);
+			if (uri == NULL) {
+			    if (ctxt->error != NULL)
+				ctxt->error(ctxt->userData,
+				"Attribute %s contains invalid URI %s\n",
+					    cur->name, val);
+			    ctxt->nbErrors++;
+			} else {
+			    if (uri->scheme == NULL) {
+				if (ctxt->error != NULL)
+				    ctxt->error(ctxt->userData,
+				    "Attribute %s URI %s is not absolute\n",
+						cur->name, val);
+				ctxt->nbErrors++;
+			    }
+			    if (uri->fragment != NULL) {
+				if (ctxt->error != NULL)
+				    ctxt->error(ctxt->userData,
+				    "Attribute %s URI %s has a fragment ID\n",
+						cur->name, val);
+				ctxt->nbErrors++;
+			    }
+			    xmlFreeURI(uri);
+			}
+		    }
+		    xmlFree(val);
+		}
+	    } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
+		if (ctxt->error != NULL)
+		    ctxt->error(ctxt->userData,
+			    "Unknown attribute %s on %s\n",
+				cur->name, node->name);
+		ctxt->nbErrors++;
+	    }
+	}
+	cur = next;
+    }
+}
+
+/**
  * xmlRelaxNGCleanupDoc:
  * @ctxt:  a Relax-NG parser context
  * @doc:  an xmldocPtr document pointer
@@ -3497,9 +3830,21 @@
 	     */
 	    if ((cur->ns == NULL) ||
 		(!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
+		if ((cur->parent != NULL) &&
+		    (cur->parent->type == XML_ELEMENT_NODE) &&
+		    ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
+		     (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
+		     (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
+		    if (ctxt->error != NULL)
+			ctxt->error(ctxt->userData,
+				"element %s doesn't allow foreign elements\n",
+				    cur->parent->name);
+		    ctxt->nbErrors++;
+		}
 		delete = cur;
 		goto skip_children;
 	    } else {
+		xmlRelaxNGCleanupAttributes(ctxt, cur);
 		if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
 		    xmlChar *href, *ns, *base, *URL;
 		    xmlRelaxNGDocumentPtr docu;
@@ -5349,7 +5694,11 @@
 	    ctxt->state->value = oldvalue;
 	    if (ret == -1) {
 		VALID_CTXT();
-		VALID_ERROR2("internal error validating %s\n", define->name);
+		if (define->name != NULL) {
+		    VALID_ERROR2("error validating value %s\n", define->name);
+		} else {
+		    VALID_ERROR("error validating value\n");
+		}
 	    } else if (ret == 0) {
 		ctxt->state->seq = node->next;
 	    }