more work on the RelaxNG implementation conformance testing. found 373

* relaxng.c check-relaxng-test-suite.py: more work on the
  RelaxNG implementation conformance testing.
  found 373 test schemas: 284 success 89 failures
  found 529 test instances: 448 success 47 failures
* result/relaxng/*: updated the results
Daniel
diff --git a/relaxng.c b/relaxng.c
index 36cec74..d6f1f17 100644
--- a/relaxng.c
+++ b/relaxng.c
@@ -54,6 +54,7 @@
 /* #define DEBUG_TYPE 1 */
 /* #define DEBUG_VALID 1 */
 /* #define DEBUG_INTERLEAVE 1 */
+/* #define DEBUG_LIST 1 */
 
 #define UNBOUNDED (1 << 30)
 #define TODO 								\
@@ -99,6 +100,9 @@
     XML_RELAXNG_NOT_ALLOWED,    /* not allowed top */
     XML_RELAXNG_EXCEPT,    	/* except present in nameclass defs */
     XML_RELAXNG_TEXT,		/* textual content */
+#if 0
+    XML_RELAXNG_MIXED,		/* mixed content with single sub-content */
+#endif
     XML_RELAXNG_ELEMENT,	/* an element */
     XML_RELAXNG_DATATYPE,	/* extenal data type definition */
     XML_RELAXNG_VALUE,		/* value from an extenal data type definition */
@@ -797,6 +801,7 @@
  * @ctxt: the parser context
  * @URL:  the normalized URL
  * @node: the include node.
+ * @ns:  the namespace passed from the context.
  *
  * First lookup if the document is already loaded into the parser context,
  * check against recursion. If not found the resource is loaded and
@@ -806,7 +811,7 @@
  */
 static xmlRelaxNGIncludePtr
 xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
-	              xmlNodePtr node) {
+	              xmlNodePtr node, const xmlChar *ns) {
     xmlRelaxNGIncludePtr ret = NULL;
     xmlDocPtr doc;
     int i;
@@ -839,7 +844,10 @@
 	    return(NULL);
 	}
     } else {
-	ret = xmlHashLookup(ctxt->includes, URL);
+	if (ns == NULL)
+	    ret = xmlHashLookup2(ctxt->includes, BAD_CAST "", URL);
+	else
+	    ret = xmlHashLookup2(ctxt->includes, ns, URL);
 	if (ret != NULL)
 	    return(ret);
     }
@@ -874,9 +882,24 @@
     ret->href = xmlStrdup(URL);
 
     /*
+     * transmit the ns if needed
+     */
+    if (ns != NULL) {
+	root = xmlDocGetRootElement(doc);
+	if (root != NULL) {
+	    if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
+		xmlSetProp(root, BAD_CAST"ns", ns);
+	    }
+	}
+    }
+
+    /*
      * push it on the stack and register it in the hash table
      */
-    xmlHashAddEntry(ctxt->includes, URL, ret);
+    if (ns == NULL)
+	xmlHashAddEntry2(ctxt->includes, BAD_CAST "", URL, ret);
+    else
+	xmlHashAddEntry2(ctxt->includes, ns, URL, ret);
     xmlRelaxNGIncludePush(ctxt, ret);
 
     /*
@@ -1793,7 +1816,7 @@
  */
 static xmlRelaxNGDefinePtr
 xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
-    xmlRelaxNGDefinePtr def = NULL;
+    xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
     xmlRelaxNGTypeLibraryPtr lib;
     xmlChar *type;
     xmlChar *library;
@@ -1858,11 +1881,64 @@
 	}
     }
     content = node->children;
+
+    /*
+     * Handle optional params
+     */
     while (content != NULL) {
+	if (!xmlStrEqual(content->name, BAD_CAST "param"))
+	    break;
 	TODO
 	ctxt->nbErrors++;
 	content = content->next;
     }
+    /*
+     * Handle optional except
+     */
+    if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
+	xmlNodePtr child;
+	xmlRelaxNGDefinePtr tmp2, last2 = NULL;
+
+	except = xmlRelaxNGNewDefine(ctxt, node);
+	if (except == NULL) {
+	    return(def);
+	}
+	except->type = XML_RELAXNG_EXCEPT;
+	child = content->children;
+	if (last == NULL) {
+	    def->content = except;
+	} else {
+	    last->next = except;
+	}
+	if (child == NULL) {
+	    if (ctxt->error != NULL)
+		ctxt->error(ctxt->userData,
+		    "except has no content\n");
+	    ctxt->nbErrors++;
+	}
+	while (child != NULL) {
+	    tmp2 = xmlRelaxNGParsePattern(ctxt, child);
+	    if (tmp2 != NULL) {
+		if (last2 == NULL) {
+		    except->content = last2 = tmp2;
+		} else {
+		    last2->next = tmp2;
+		    last2 = tmp2;
+		}
+	    }
+	    child = child->next;
+	}
+	content = content->next;
+    }
+    /*
+     * Check there is no unhandled data
+     */
+    if (content != NULL) {
+	if (ctxt->error != NULL)
+	    ctxt->error(ctxt->userData,
+		"Element data has unexpected content %s\n", content->name);
+	ctxt->nbErrors++;
+    }
 
     return(def);
 }
@@ -2693,8 +2769,31 @@
 	    }
 	}
     } else if (IS_RELAXNG(node, "mixed")) {
-	TODO
-	ctxt->nbErrors++;
+	if (node->children == NULL) {
+	    if (ctxt->error != NULL)
+		ctxt->error(ctxt->userData,
+		    "Mixed is empty\n");
+	    ctxt->nbErrors++;
+	    def = NULL;
+#if 0
+	} else if (node->children->next == NULL) {
+	    def = xmlRelaxNGNewDefine(ctxt, node);
+	    if (def == NULL)
+		return(NULL);
+	    def->type = XML_RELAXNG_MIXED;
+#endif
+	} else {
+	    def = xmlRelaxNGParseInterleave(ctxt, node);
+	    if (def != NULL) {
+		xmlRelaxNGDefinePtr tmp;
+		tmp = xmlRelaxNGNewDefine(ctxt, node);
+		if (tmp == NULL)
+		    return(def);
+		tmp->type = XML_RELAXNG_TEXT;
+		tmp->next = def->content;
+		def->content = tmp;
+	    }
+	}
     } else {
 	if (ctxt->error != NULL)
 	    ctxt->error(ctxt->userData,
@@ -2760,6 +2859,9 @@
 		case XML_RELAXNG_OPTIONAL:
 		case XML_RELAXNG_CHOICE:
 		case XML_RELAXNG_GROUP:
+#if 0
+		case XML_RELAXNG_MIXED:
+#endif
 		case XML_RELAXNG_INTERLEAVE:
 		    ret->content = cur;
 		    cur->parent = ret;
@@ -2890,6 +2992,23 @@
 	ret->name = val;
 	val = xmlGetProp(node, BAD_CAST "ns");
 	ret->ns = val;
+	if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
+	    (val != NULL) &&
+	    (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
+	    ctxt->error(ctxt->userData,
+		"Attribute with namespace '%s' is not allowed\n",
+			val);
+	    ctxt->nbErrors++;
+	}
+	if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
+	    (val != NULL) &&
+	    (val[0] == 0) &&
+	    (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
+	    ctxt->error(ctxt->userData,
+		"Attribute with QName 'xmlns' is not allowed\n",
+			val);
+	    ctxt->nbErrors++;
+	}
     } else if (IS_RELAXNG(node, "anyName")) {
 	ret->name = NULL;
 	ret->ns = NULL;
@@ -2907,6 +3026,14 @@
 		    "nsName has no ns attribute\n");
 	    ctxt->nbErrors++;
 	}
+	if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
+	    (ret->ns != NULL) &&
+	    (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
+	    ctxt->error(ctxt->userData,
+		"Attribute with namespace '%s' is not allowed\n",
+			ret->ns);
+	    ctxt->nbErrors++;
+	}
 	if (node->children != NULL) {
 	    ret->nameClass =
 		xmlRelaxNGParseExceptNameClass(ctxt, node->children,
@@ -2924,8 +3051,7 @@
 
 	    child = node->children;
 	    while (child != NULL) {
-		tmp = xmlRelaxNGParseExceptNameClass(ctxt, child,
-				   (def->type == XML_RELAXNG_ATTRIBUTE));
+		tmp = xmlRelaxNGParseNameClass(ctxt, child, def);
 		if (tmp != NULL) {
 		    if (last == NULL) {
 			last = ret->nameClass = tmp;
@@ -3011,6 +3137,9 @@
 		case XML_RELAXNG_OPTIONAL:
 		case XML_RELAXNG_CHOICE:
 		case XML_RELAXNG_GROUP:
+#if 0
+		case XML_RELAXNG_MIXED:
+#endif
 		case XML_RELAXNG_INTERLEAVE:
 		    if (last == NULL) {
 			ret->content = last = cur;
@@ -3905,8 +4034,19 @@
 		if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
 		    xmlChar *href, *ns, *base, *URL;
 		    xmlRelaxNGDocumentPtr docu;
+		    xmlNodePtr tmp;
 
 		    ns = xmlGetProp(cur, BAD_CAST "ns");
+		    if (ns == NULL) {
+			tmp = cur->parent;
+			while ((tmp != NULL) &&
+			       (tmp->type == XML_ELEMENT_NODE)) {
+			    ns = xmlGetProp(tmp, BAD_CAST "ns");
+			    if (ns != NULL)
+				break;
+			    tmp = tmp->parent;
+			}
+		    }
 		    href = xmlGetProp(cur, BAD_CAST "href");
 		    if (href == NULL) {
 			if (ctxt->error != NULL)
@@ -3947,8 +4087,9 @@
 		    xmlFree(URL);
 		    cur->_private = docu;
 		} else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
-		    xmlChar *href, *base, *URL;
+		    xmlChar *href, *ns, *base, *URL;
 		    xmlRelaxNGIncludePtr incl;
+		    xmlNodePtr tmp;
 
 		    href = xmlGetProp(cur, BAD_CAST "href");
 		    if (href == NULL) {
@@ -3977,7 +4118,20 @@
 			xmlFree(href);
 		    if (base != NULL)
 			xmlFree(base);
-		    incl = xmlRelaxNGLoadInclude(ctxt, URL, cur);
+		    ns = xmlGetProp(cur, BAD_CAST "ns");
+		    if (ns == NULL) {
+			tmp = cur->parent;
+			while ((tmp != NULL) &&
+			       (tmp->type == XML_ELEMENT_NODE)) {
+			    ns = xmlGetProp(tmp, BAD_CAST "ns");
+			    if (ns != NULL)
+				break;
+			    tmp = tmp->parent;
+			}
+		    }
+		    incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
+		    if (ns != NULL)
+			xmlFree(ns);
 		    if (incl == NULL) {
 			if (ctxt->error != NULL)
 			    ctxt->error(ctxt->userData,
@@ -4094,19 +4248,30 @@
 		 * into a div
 		 */
 		if (xmlStrEqual(cur->name, BAD_CAST "div")) {
+		    xmlChar *ns;
+		    xmlNodePtr child, ins, tmp;
+
 		    /*
 		     * implements rule 4.11
 		     */
-		    xmlNodePtr child, ins, tmp;
+
+		    ns = xmlGetProp(cur, BAD_CAST "ns");
 
 		    child = cur->children;
 		    ins = cur;
 		    while (child != NULL) {
+			if (ns != NULL) {
+			    if (!xmlHasProp(child, BAD_CAST "ns")) {
+				xmlSetProp(child, BAD_CAST "ns", ns);
+			    }
+			}
 			tmp = child->next;
 			xmlUnlinkNode(child);
 			ins = xmlAddNextSibling(ins, child);
 			child = tmp;
 		    }
+		    if (ns != NULL)
+			xmlFree(ns);
 		    delete = cur;
 		    goto skip_children;
 		}
@@ -4427,10 +4592,17 @@
 	    fprintf(output, "</parentRef>\n");
 	    break;
 	case XML_RELAXNG_EXTERNALREF:
-	    fprintf(output, "<externalRef");
+	    fprintf(output, "<externalRef>");
 	    xmlRelaxNGDumpDefines(output, define->content);
 	    fprintf(output, "</externalRef>\n");
 	    break;
+#if 0
+	case XML_RELAXNG_MIXED:
+	    fprintf(output, "<mixed>");
+	    xmlRelaxNGDumpDefines(output, define->content);
+	    fprintf(output, "</mixed>\n");
+	    break;
+#endif
         case XML_RELAXNG_DATATYPE:
         case XML_RELAXNG_VALUE:
 	    TODO
@@ -4653,6 +4825,17 @@
 	return(-1);
 	ret = -1;
     }
+    if ((ret == 0) && (define->content != NULL)) {
+	const xmlChar *oldvalue, *oldendvalue;
+
+	oldvalue = ctxt->state->value;
+	oldendvalue = ctxt->state->endvalue;
+	ctxt->state->value = (xmlChar *) value;
+	ctxt->state->endvalue = NULL;
+	ret = xmlRelaxNGValidateValue(ctxt, define->content);
+	ctxt->state->value = (xmlChar *) oldvalue;
+	ctxt->state->endvalue = (xmlChar *) oldendvalue;
+    }
     return(ret);
 }
 
@@ -4769,6 +4952,8 @@
 			xmlFree(nvalue);
 		}
 	    }
+	    if (ret == 0)
+		xmlRelaxNGNextValue(ctxt);
 	    break;
 	}
 	case XML_RELAXNG_DATATYPE: {
@@ -4795,11 +4980,16 @@
 		list = list->next;
 	    }
 	    ctxt->flags = oldflags;
+	    if (ret == 0)
+		xmlRelaxNGNextValue(ctxt);
 	    break;
 	}
 	case XML_RELAXNG_LIST: {
 	    xmlRelaxNGDefinePtr list = define->content;
 	    xmlChar *oldvalue, *oldend, *val, *cur;
+#ifdef DEBUG_LIST
+	    int nb_values = 0;
+#endif
 
 	    oldvalue = ctxt->state->value;
 	    oldend = ctxt->state->endvalue;
@@ -4812,10 +5002,22 @@
 	    }
 	    cur = val;
 	    while (*cur != 0) {
-		if (IS_BLANK(*cur))
+		if (IS_BLANK(*cur)) {
 		    *cur = 0;
-		cur++;
+		    cur++;
+#ifdef DEBUG_LIST
+		    nb_values++;
+#endif
+		    while (IS_BLANK(*cur))
+			*cur++ = 0;
+		} else
+		    cur++;
 	    }
+#ifdef DEBUG_LIST
+	    xmlGenericError(xmlGenericErrorContext,
+		    "list value: '%s' found %d items\n", oldvalue, nb_values);
+	    nb_values = 0;
+#endif 
 	    ctxt->state->endvalue = cur;
 	    cur = val;
 	    while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
@@ -4825,8 +5027,16 @@
 	    while (list != NULL) {
 		ret = xmlRelaxNGValidateValue(ctxt, list);
 		if (ret != 0) {
+#ifdef DEBUG_LIST
+		    xmlGenericError(xmlGenericErrorContext,
+			"Failed to validate value: '%s' with %d rule\n",
+		                    ctxt->state->value, nb_values);
+#endif
 		    break;
 		}
+#ifdef DEBUG_LIST
+		nb_values++;
+#endif
 		list = list->next;
 	    }
 	    if ((ret == 0) && (ctxt->state->value != NULL) &&
@@ -4867,6 +5077,21 @@
 	    ctxt->flags = oldflags;
 	    break;
 	}
+        case XML_RELAXNG_EXCEPT: {
+	    xmlRelaxNGDefinePtr list;
+
+	    list = define->content;
+	    while (list != NULL) {
+		ret = xmlRelaxNGValidateValue(ctxt, list);
+		if (ret == 0) {
+		    ret = -1;
+		    break;
+		} else 
+		    ret = 0;
+		list = list->next;
+	    }
+	    break;
+	}
 	default:
 	    TODO
 	    ret = -1;
@@ -5433,6 +5658,80 @@
 }
 
 /**
+ * xmlRelaxNGElementMatch:
+ * @ctxt:  a Relax-NG validation context
+ * @define:  the definition to check
+ * @elem:  the element
+ *
+ * Check if the element matches the definition nameClass
+ *
+ * Returns 1 if the element matches, 0 if no, or -1 in case of error
+ */
+static int
+xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, 
+	               xmlRelaxNGDefinePtr define,
+		       xmlNodePtr elem) {
+    int ret, oldflags;
+
+    if (define->name != NULL) {
+	if (!xmlStrEqual(elem->name, define->name)) {
+	    VALID_CTXT();
+	    VALID_ERROR3("Expecting element %s, got %s\n",
+			define->name, elem->name);
+	    return(0);
+	}
+    }
+    if ((define->ns != NULL) && (define->ns[0] != 0)) {
+	if (elem->ns == NULL) {
+	    VALID_CTXT();
+	    VALID_ERROR2("Expecting a namespace for element %s\n",
+			elem->name);
+	    return(0);
+	} else if (!xmlStrEqual(elem->ns->href, define->ns)) {
+	    VALID_CTXT();
+	    VALID_ERROR3("Expecting element %s has wrong namespace: expecting %s\n",
+			elem->name, define->ns);
+	    return(0);
+	}
+    } else if (define->name != NULL) {
+	if (elem->ns != NULL) {
+	    VALID_CTXT();
+	    VALID_ERROR2("Expecting no namespace for element %s\n",
+			define->name);
+	    return(0);
+	}
+    }
+
+    if (define->nameClass == NULL)
+	return(1);
+
+    define = define->nameClass;
+    if (define->type == XML_RELAXNG_EXCEPT) {
+	xmlRelaxNGDefinePtr list;
+	oldflags = ctxt->flags;
+	ctxt->flags |= FLAGS_IGNORABLE;
+
+	list = define->content;
+	while (list != NULL) {
+	    ret = xmlRelaxNGElementMatch(ctxt, list, elem);
+	    if (ret == 1) {
+		ctxt->flags = oldflags;
+		return(0);
+	    }
+	    if (ret < 0) {
+		ctxt->flags = oldflags;
+		return(ret);
+	    }
+	    list = list->next;
+	}
+	ctxt->flags = oldflags;
+    } else {
+	TODO
+    }
+    return(1);
+}
+
+/**
  * xmlRelaxNGValidateDefinition:
  * @ctxt:  a Relax-NG validation context
  * @define:  the definition to verify
@@ -5522,38 +5821,13 @@
 	     */
 	    if (node->_private == define)
 		break;
-	    if (define->name != NULL) {
-		if (!xmlStrEqual(node->name, define->name)) {
-		    VALID_CTXT();
-		    VALID_ERROR3("Expecting element %s, got %s\n",
-			        define->name, node->name);
-		    ret = -1;
-		    break;
-		}
+
+	    ret = xmlRelaxNGElementMatch(ctxt, define, node);
+	    if (ret <= 0) {
+		ret = -1;
+		break;
 	    }
-	    if ((define->ns != NULL) && (define->ns[0] != 0)) {
-		if (node->ns == NULL) {
-		    VALID_CTXT();
-		    VALID_ERROR2("Expecting a namespace for element %s\n",
-			        node->name);
-		    ret = -1;
-		    break;
-		} else if (!xmlStrEqual(node->ns->href, define->ns)) {
-		    VALID_CTXT();
-		    VALID_ERROR3("Expecting element %s has wrong namespace: expecting %s\n",
-			        node->name, define->ns);
-		    ret = -1;
-		    break;
-		}
-	    } else if (define->name != NULL) {
-		if (node->ns != NULL) {
-		    VALID_CTXT();
-		    VALID_ERROR2("Expecting no namespace for element %s\n",
-			        define->name);
-		    ret = -1;
-		    break;
-		}
-	    }
+	    ret = 0;
 	    
 	    state = xmlRelaxNGNewValidState(ctxt, node);
 	    if (state == NULL) {
@@ -5833,9 +6107,16 @@
 		xmlFree(content);
 	    break;
         }
+#if 0
+	case XML_RELAXNG_MIXED:
+	    TODO
+	    ret = -1;
+	    break;
+#endif
 	case XML_RELAXNG_START:
 	case XML_RELAXNG_EXCEPT:
 	    TODO
+	    ret = -1;
 	    break;
     }
     ctxt->depth--;