more bug fixes, improve the error reporting. second test Daniel

* schematron.c: more bug fixes, improve the error reporting.
* test/schematron/zvon2* result/schematron/zvon2*: second test
Daniel
diff --git a/ChangeLog b/ChangeLog
index 49d59d6..a53ed8c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Sun Jul 31 15:42:31 CEST 2005 Daniel Veillard <daniel@veillard.com>
+
+	* schematron.c: more bug fixes, improve the error reporting.
+	* test/schematron/zvon2* result/schematron/zvon2*: second test
+
 Sun Jul 31 14:15:31 CEST 2005 Daniel Veillard <daniel@veillard.com>
 
 	* schematron.c xmllint.c: fixing the loop bug, fixing schematron
diff --git a/result/schematron/zvon2_0 b/result/schematron/zvon2_0
new file mode 100644
index 0000000..695bc8f
--- /dev/null
+++ b/result/schematron/zvon2_0
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<AAA>
+     <BBB>bbbb</BBB>
+     <CCC>cccc</CCC>
+</AAA>
diff --git a/result/schematron/zvon2_0.err b/result/schematron/zvon2_0.err
new file mode 100644
index 0000000..f4e4a7f
--- /dev/null
+++ b/result/schematron/zvon2_0.err
@@ -0,0 +1,2 @@
+Pattern: Character @ forbidden
+./test/schematron/zvon2_0.xml validates
diff --git a/result/schematron/zvon2_1 b/result/schematron/zvon2_1
new file mode 100644
index 0000000..2af2cd0
--- /dev/null
+++ b/result/schematron/zvon2_1
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<AAA>
+     <BBB>bbbb@bbb.com</BBB>
+     <CCC>ccc@ccc.com</CCC>
+</AAA>
diff --git a/result/schematron/zvon2_1.err b/result/schematron/zvon2_1.err
new file mode 100644
index 0000000..28f3e99
--- /dev/null
+++ b/result/schematron/zvon2_1.err
@@ -0,0 +1,5 @@
+Pattern: Character @ forbidden
+/AAA line 1: Text in element AAA must not contain character @ 
+/AAA/BBB line 2: Text in element BBB must not contain character @ 
+/AAA/CCC line 3: Text in element CCC must not contain character @ 
+./test/schematron/zvon2_1.xml fails to validate
diff --git a/result/schematron/zvon2_2 b/result/schematron/zvon2_2
new file mode 100644
index 0000000..585cf0c
--- /dev/null
+++ b/result/schematron/zvon2_2
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<AAA>
+     <BBB>bbbb</BBB>
+     <CCC>cccc</CCC>
+     aaa@aaa.net
+</AAA>
diff --git a/result/schematron/zvon2_2.err b/result/schematron/zvon2_2.err
new file mode 100644
index 0000000..40dc7ca
--- /dev/null
+++ b/result/schematron/zvon2_2.err
@@ -0,0 +1,3 @@
+Pattern: Character @ forbidden
+/AAA line 1: Text in element AAA must not contain character @ 
+./test/schematron/zvon2_2.xml fails to validate
diff --git a/schematron.c b/schematron.c
index 312dfc5..b5c6618 100644
--- a/schematron.c
+++ b/schematron.c
@@ -128,7 +128,7 @@
  */
 struct _xmlSchematron {
     const xmlChar *name;	/* schema name */
-    int preserve;		/* was the document preserved by the user */
+    int preserve;		/* was the document passed by the user */
     xmlDocPtr doc;		/* pointer to the parsed document */
     int flags;			/* specific to this schematron */
 
@@ -1089,6 +1089,7 @@
                           ctxt->URL, NULL);
             return (NULL);
         }
+	ctxt->preserve = 0;
     } else if (ctxt->buffer != NULL) {
         doc = xmlReadMemory(ctxt->buffer, ctxt->size, NULL, NULL,
 	                    SCHEMATRON_PARSE_OPTIONS);
@@ -1101,9 +1102,11 @@
         }
         doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
         ctxt->URL = xmlDictLookup(ctxt->dict, BAD_CAST "in_memory_buffer", -1);
+	ctxt->preserve = 0;
     } else if (ctxt->doc != NULL) {
         doc = ctxt->doc;
 	preserve = 1;
+	ctxt->preserve = 1;
     } else {
 	xmlSchematronPErr(ctxt, NULL,
 		      XML_SCHEMAP_NOTHING_TO_PARSE,
@@ -1196,6 +1199,9 @@
 	    ctxt->URL, NULL);
 	goto exit;
     }
+    /* the original document must be kept for reporting */
+    ret->doc = doc;
+    preserve = 1;
 
 exit:
     if (!preserve) {
@@ -1235,6 +1241,72 @@
 }
 
 /**
+ * xmlSchematronFormatReport:
+ * @ctxt:  the validation context
+ * @test: the test node
+ * @cur: the current node tested
+ *
+ * Build the string being reported to the user.
+ *
+ * Returns a report string or NULL in case of error. The string needs
+ *         to be deallocated by teh caller
+ */
+static xmlChar *
+xmlSchematronFormatReport(xmlSchematronValidCtxtPtr ctxt, 
+			  xmlNodePtr test, xmlNodePtr cur) {
+    xmlChar *ret = NULL;
+    xmlNodePtr child;
+
+    if ((test == NULL) || (cur == NULL))
+        return(ret);
+
+    child = test->children;
+    while (child != NULL) {
+        if ((child->type == XML_TEXT_NODE) ||
+	    (child->type == XML_CDATA_SECTION_NODE))
+	    ret = xmlStrcat(ret, child->content);
+	else if (IS_SCHEMATRON(child, "name")) {
+	    if ((cur->ns == NULL) || (cur->ns->prefix == NULL)) 
+	        ret = xmlStrcat(ret, cur->name);
+	    else {
+	        ret = xmlStrcat(ret, cur->ns->prefix);
+	        ret = xmlStrcat(ret, BAD_CAST ":");
+	        ret = xmlStrcat(ret, cur->name);
+	    }
+	} else {
+	    child = child->next;
+	    continue;
+	}
+
+	/*
+	 * remove superfluous \n
+	 */
+	if (ret != NULL) {
+	    int len = xmlStrlen(ret);
+	    xmlChar c;
+
+	    if (len > 0) {
+		c = ret[len - 1];
+		if ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t')) {
+		    while ((c == ' ') || (c == '\n') ||
+		           (c == '\r') || (c == '\t')) {
+			len--;
+			if (len == 0)
+			    break;
+			c = ret[len - 1];
+		    }
+		    ret[len] = ' ';
+		    ret[len + 1] = 0;
+		}
+	    }
+	}
+
+        child = child->next;
+    }
+    return(ret);
+}
+
+/**
  * xmlSchematronReportSuccess:
  * @ctxt:  the validation context
  * @test: the compiled test
@@ -1260,7 +1332,7 @@
         xmlChar *path;
 	char msg[1000];
 	long line;
-	const xmlChar *report;
+	const xmlChar *report = NULL;
 
         if (((test->type == XML_SCHEMATRON_REPORT) & (!success)) ||
 	    ((test->type == XML_SCHEMATRON_ASSERT) & (success)))
@@ -1269,15 +1341,25 @@
 	path = xmlGetNodePath(cur);
 	if (path == NULL)
 	    path = (xmlChar *) cur->name;
+#if 0
 	if ((test->report != NULL) && (test->report[0] != 0))
 	    report = test->report;
-	else if (test->type == XML_SCHEMATRON_ASSERT) {
-	    report = BAD_CAST "node failed assert";
+#endif
+	if (test->node != NULL)
+            report = xmlSchematronFormatReport(ctxt, test->node, cur);
+	if (report == NULL) {
+	    if (test->type == XML_SCHEMATRON_ASSERT) {
+		snprintf(msg, 999, "%s line %ld: node failed assert\n",
+		         (const char *) path, line);
+	    } else {
+		snprintf(msg, 999, "%s line %ld: node failed report\n",
+		         (const char *) path, line);
+	    }
 	} else {
-	    report = BAD_CAST "node failed report";
+	    snprintf(msg, 999, "%s line %ld: %s\n", (const char *) path,
+		     line, (const char *) report);
+	    xmlFree(report);
 	}
-	snprintf(msg, 999, "%s line %ld: %s\n", (const char *) path,
-	         line, (const char *) report);
 	xmlSchematronReportOutput(ctxt, cur, &msg[0]);
 	if ((path != NULL) && (path != (xmlChar *) cur->name))
 	    xmlFree(path);
@@ -1436,36 +1518,42 @@
     ret = xmlXPathCompiledEval(test->comp, ctxt->xctxt);
     if (ret == NULL) {
 	failed = 1;
-    } else switch (ret->type) {
-	case XPATH_XSLT_TREE:
-	case XPATH_NODESET:
-	    if ((ret->nodesetval == NULL) ||
-		(ret->nodesetval->nodeNr == 0))
+    } else {
+        switch (ret->type) {
+	    case XPATH_XSLT_TREE:
+	    case XPATH_NODESET:
+		if ((ret->nodesetval == NULL) ||
+		    (ret->nodesetval->nodeNr == 0))
+		    failed = 1;
+		break;
+	    case XPATH_BOOLEAN:
+		failed = !ret->boolval;
+		break;
+	    case XPATH_NUMBER:
+		if ((xmlXPathIsNaN(ret->floatval)) ||
+		    (ret->floatval == 0.0))
+		    failed = 1;
+		break;
+	    case XPATH_STRING:
+		if ((ret->stringval == NULL) ||
+		    (ret->stringval[0] == 0))
+		    failed = 1;
+		break;
+	    case XPATH_UNDEFINED:
+	    case XPATH_POINT:
+	    case XPATH_RANGE:
+	    case XPATH_LOCATIONSET:
+	    case XPATH_USERS:
 		failed = 1;
-	    break;
-	case XPATH_BOOLEAN:
-	    failed = !ret->boolval;
-	    break;
-	case XPATH_NUMBER:
-	    if ((xmlXPathIsNaN(ret->floatval)) ||
-		(ret->floatval == 0.0))
-		failed = 1;
-	    break;
-	case XPATH_STRING:
-	    if ((ret->stringval == NULL) ||
-		(ret->stringval[0] == 0))
-		failed = 1;
-	    break;
-	case XPATH_UNDEFINED:
-	case XPATH_POINT:
-	case XPATH_RANGE:
-	case XPATH_LOCATIONSET:
-	case XPATH_USERS:
-	    failed = 1;
-	    break;
+		break;
+	}
+	xmlXPathFreeObject(ret);
     }
-    if (failed) 
+    if ((failed) && (test->type == XML_SCHEMATRON_ASSERT))
         ctxt->nberrors++;
+    else if ((!failed) && (test->type == XML_SCHEMATRON_REPORT))
+        ctxt->nberrors++;
+
     xmlSchematronReportSuccess(ctxt, test, cur, !failed);
 
     return(!failed);
diff --git a/test/schematron/zvon2.sct b/test/schematron/zvon2.sct
new file mode 100644
index 0000000..56974a0
--- /dev/null
+++ b/test/schematron/zvon2.sct
@@ -0,0 +1,9 @@
+<schema xmlns="http://www.ascc.net/xml/schematron" >
+     <pattern name="Character @ forbidden">
+          <rule context="*">
+               <report test="contains(.,'@')">Text in element
+                    <name/> must not contain character @
+               </report>
+          </rule>
+     </pattern>
+</schema>
diff --git a/test/schematron/zvon2_0.xml b/test/schematron/zvon2_0.xml
new file mode 100644
index 0000000..832c507
--- /dev/null
+++ b/test/schematron/zvon2_0.xml
@@ -0,0 +1,4 @@
+<AAA>
+     <BBB>bbbb</BBB>
+     <CCC>cccc</CCC>
+</AAA>
diff --git a/test/schematron/zvon2_1.xml b/test/schematron/zvon2_1.xml
new file mode 100644
index 0000000..6ade195
--- /dev/null
+++ b/test/schematron/zvon2_1.xml
@@ -0,0 +1,4 @@
+<AAA>
+     <BBB>bbbb@bbb.com</BBB>
+     <CCC>ccc@ccc.com</CCC>
+</AAA>
diff --git a/test/schematron/zvon2_2.xml b/test/schematron/zvon2_2.xml
new file mode 100644
index 0000000..812d44a
--- /dev/null
+++ b/test/schematron/zvon2_2.xml
@@ -0,0 +1,5 @@
+<AAA>
+     <BBB>bbbb</BBB>
+     <CCC>cccc</CCC>
+     aaa@aaa.net
+</AAA>