Added output of canonical values in identity-constraint error messages.

* xmlschemas.c: Added output of canonical values in
  identity-constraint error messages.
* xmlschemastypes.c include/libxml/xmlschemastypes.h:
  Added xmlSchemaGetCanonValueWhtsp() to the API.
  Further enhancement of the canonical value
  conversion.
* test/schemas/changelog093_0.*: Added test with an XSD
  submitted by Randy J. Ray.
diff --git a/ChangeLog b/ChangeLog
index a4a9b1d..6b62979 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+Mon Apr 18 12:42:14 CEST 2005 Kasimier Buchcik <libxml2-cvs@cazic.net>
+
+	* xmlschemas.c: Added output of canonical values in
+	  identity-constraint error messages.
+	* xmlschemastypes.c include/libxml/xmlschemastypes.h:
+	  Added xmlSchemaGetCanonValueWhtsp() to the API.
+	  Further enhancement of the canonical value
+	  conversion.
+	* test/schemas/changelog093_0.*: Added test with an XSD
+	  submitted by Randy J. Ray.
+
 Fri Apr 15 09:33:21 HKT 2005 William Brack <wbrack@mmm.com.hk>
 
 	* valid.c: Applied Daniel's fix for memory leak in dtd
diff --git a/include/libxml/xmlschemastypes.h b/include/libxml/xmlschemastypes.h
index 18014fe..ea679ab 100644
--- a/include/libxml/xmlschemastypes.h
+++ b/include/libxml/xmlschemastypes.h
@@ -111,6 +111,10 @@
 XMLPUBFUN int XMLCALL
 		xmlSchemaGetCanonValue		(xmlSchemaValPtr val,
 						 const xmlChar **retValue);
+XMLPUBFUN int XMLCALL
+		xmlSchemaGetCanonValueWhtsp	(xmlSchemaValPtr val,						 
+						 const xmlChar **retValue,
+						 xmlSchemaWhitespaceValueType ws);
 XMLPUBFUN xmlSchemaValPtr XMLCALL
 		xmlSchemaNewStringValue		(xmlSchemaValType type,
 						 const xmlChar *value);
diff --git a/test/schemas/changelog093_0.xml b/test/schemas/changelog093_0.xml
new file mode 100644
index 0000000..4b49612
--- /dev/null
+++ b/test/schemas/changelog093_0.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<changelog
+	xmlns="http://www.blackperl.com/XML/ChangeLog" 
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.blackperl.com/XML/ChangeLog changelog093.xsd">
+	<description lang="PL"/>
+	<description lang="PL"/>
+	<release version="1" date="2005-04-08T21:12:00">
+		<item>
+			<file path="abc"/>
+			<description lang="FR"/>
+		</item>
+	</release>
+</changelog>
diff --git a/test/schemas/changelog093_1.xsd b/test/schemas/changelog093_1.xsd
new file mode 100644
index 0000000..cf2bcc6
--- /dev/null
+++ b/test/schemas/changelog093_1.xsd
@@ -0,0 +1,253 @@
+<?xml version="1.0"?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    xmlns:tns="http://www.blackperl.com/XML/ChangeLog"
+    targetNamespace="http://www.blackperl.com/XML/ChangeLog"
+    elementFormDefault="qualified" attributeFormDefault="unqualified"
+    version="0.93" id="changelog0.93">
+  <!--
+      Refer to this schema using the following namespace:
+      http://www.blackperl.com/XML/ChangeLog
+  -->
+  <xsd:annotation>
+    <xsd:documentation>
+      A description of an XML application which itemizes changes over the
+      life-span of a software project. Changes are tracked by releases, with a
+      granularity of individual items made up of files that were affected.
+    </xsd:documentation>
+    <xsd:appinfo xmlns:dc="http://purl.org/dc/elements/1.1/">
+      <dc:creator>Randy J. Ray (rjray@blackperl.com)</dc:creator>
+      <dc:date>2004-11-22</dc:date>
+      <dc:subject>changelog,xml,schema</dc:subject>
+      <dc:description>
+        An XML Schema declaration describing an XML expression of software
+        project change-logs.
+      </dc:description>
+    </xsd:appinfo>
+    <xsd:appinfo>
+      <rdf:RDF xmlns:cc="http://web.resource.org/cc/"
+               xmlns:dc="http://purl.org/dc/elements/1.1/"
+               xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+        <cc:Work rdf:about="">
+          <dc:title>XML Schema for Changelogs</dc:title>
+          <dc:description>
+            An XML Schema declaration describing an XML expression of software
+            project change-logs.
+          </dc:description>
+          <dc:creator>
+            <cc:Agent>
+              <dc:title>Randy J. Ray</dc:title>
+            </cc:Agent>
+          </dc:creator>
+          <dc:rights>
+            <cc:Agent>
+              <dc:title>Randy J. Ray</dc:title>
+            </cc:Agent>
+          </dc:rights>
+          <dc:type rdf:resource="http://purl.org/dc/dcmitype/Text" />
+          <cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
+        </cc:Work>
+        <cc:License rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
+          <cc:permits rdf:resource="http://web.resource.org/cc/Reproduction" />
+          <cc:permits rdf:resource="http://web.resource.org/cc/Distribution" />
+          <cc:requires rdf:resource="http://web.resource.org/cc/Notice" />
+          <cc:requires rdf:resource="http://web.resource.org/cc/Attribution" />
+          <cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+          <cc:requires rdf:resource="http://web.resource.org/cc/ShareAlike" />
+        </cc:License>
+      </rdf:RDF>
+    </xsd:appinfo>
+  </xsd:annotation>
+
+  <xsd:complexType id="informationType" name="informationType"
+                   mixed="true">
+    <xsd:annotation>
+      <xsd:documentation>
+        An open-ended container type for including version-control information
+        at various levels within the changelog structure. This is the only
+        type which explicitly permits content from foreign namespaces.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:sequence maxOccurs="unbounded" minOccurs="0">
+      <xsd:any processContents="lax" />
+    </xsd:sequence>
+    <xsd:attribute name="source" type="xsd:anyURI" />
+    <xsd:anyAttribute namespace="##other" processContents="lax" />
+  </xsd:complexType>
+
+  <xsd:complexType id="descriptionType" name="descriptionType">
+    <xsd:annotation>
+      <xsd:documentation>
+        A description block is used to document everything from specific change
+        items to the release as a whole.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+        <xsd:attribute default="en-US" name="lang" type="xsd:language" />
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+  <xsd:simpleType id="versionString" name="versionString">
+    <xsd:annotation>
+      <xsd:documentation>
+        The versionString type is applied to attributes that describe simple
+        revision-number strings. It only supports CVS (RCS) styled version
+        numbers.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base="xsd:string">
+      <xsd:pattern value="\d+(\.\d+)*" />
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:complexType id="fileType" name="fileType">
+    <xsd:annotation>
+      <xsd:documentation>
+        The fileType definition is used for the file element, a part of the
+        itemType declaration. It is defined separately so that it can be
+        referred to from multiple places.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:sequence maxOccurs="1" minOccurs="0">
+      <xsd:element name="description" type="tns:descriptionType"
+                   minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element maxOccurs="1" minOccurs="0" name="vc-information"
+                   type="tns:informationType" nillable="true" />
+    </xsd:sequence>
+    <xsd:attribute name="path" type="xsd:string" use="required" />
+    <xsd:attribute name="revision" type="tns:versionString" use="optional"/>
+    <xsd:attribute name="author" type="xsd:NMTOKEN" use="optional" />
+    <xsd:attribute name="action" use="optional">
+      <xsd:simpleType>
+        <xsd:restriction base="xsd:NMTOKEN">
+          <xsd:enumeration value="ADD" />
+          <xsd:enumeration value="DELETE" />
+          <xsd:enumeration value="RESTORE" />
+          <xsd:enumeration value="MOVE" />
+        </xsd:restriction>
+      </xsd:simpleType>
+    </xsd:attribute>
+    <xsd:attribute name="note" type="xsd:string" use="optional" />
+  </xsd:complexType>
+
+  <xsd:element id="file" name="file" nillable="true" type="tns:fileType">
+    <xsd:annotation>
+      <xsd:documentation>
+        A file element contains a single block representing a fileType.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:unique name="fileDescriptionLangConstraint">
+      <xsd:selector xpath="tns:description" />
+      <xsd:field xpath="@lang" />
+    </xsd:unique>
+  </xsd:element>
+
+  <xsd:complexType id="itemType" name="itemType">
+    <xsd:annotation>
+      <xsd:documentation>
+        These element blocks define a single change-item within the scope of a
+        given release. A change-item consists of one or more files that were
+        affected, and a description of the change itself.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:sequence>
+      <xsd:element maxOccurs="1" minOccurs="0" name="vc-information"
+                   type="tns:informationType" nillable="true" />
+      <xsd:choice minOccurs="1" maxOccurs="1">
+        <xsd:element ref="tns:file" />
+        <xsd:element name="fileset" nillable="false">
+          <xsd:complexType>
+            <xsd:sequence>
+              <xsd:element maxOccurs="1" minOccurs="0" name="vc-information"
+                           type="tns:informationType" nillable="true" />
+              <xsd:element maxOccurs="unbounded" minOccurs="1" ref="tns:file" />
+            </xsd:sequence>
+          </xsd:complexType>
+        </xsd:element>
+      </xsd:choice>
+      <xsd:element name="description" type="tns:descriptionType"
+                   minOccurs="1" maxOccurs="unbounded" />
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID" />
+  </xsd:complexType>
+
+  <xsd:element id="item" name="item" nillable="false" type="tns:itemType">
+    <xsd:annotation>
+      <xsd:documentation>
+        An item element contains a single block representing an itemType.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:unique name="itemDescriptionLangConstraint">
+      <xsd:selector xpath="tns:description" />
+      <xsd:field xpath="@lang" />
+    </xsd:unique>
+  </xsd:element>
+
+  <xsd:complexType id="releaseType" name="releaseType">
+    <xsd:annotation>
+      <xsd:documentation>
+        The release is the primary piece of information that a changelog
+        collects and organizes. A release contains an optional description,
+        followed by one or more item blocks. The release element is also the
+        greatest user of attributes besides the file element. A release element
+        must have at least a "version" attribute, uniquely identifying the
+        release itself. Additionally, it may have "tag" to associate it with
+        a release-system tag and "date" to specify the date the release was
+        created.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:sequence>
+      <xsd:element name="description" type="tns:descriptionType"
+                   minOccurs="0" maxOccurs="unbounded" />
+      <xsd:element maxOccurs="unbounded" minOccurs="0" name="information"
+                   type="tns:informationType" nillable="true" />
+      <xsd:element maxOccurs="1" minOccurs="0" name="vc-information"
+                   type="tns:informationType" nillable="true" />
+      <xsd:element maxOccurs="unbounded" minOccurs="1" ref="tns:item" />
+    </xsd:sequence>
+    <xsd:attribute name="version" type="xsd:token" use="required" />
+    <xsd:attribute name="tag" type="xsd:NMTOKEN" />
+    <xsd:attribute name="date" type="xsd:token" use="required" /> <!-- type="xsd:dateTime"  -->
+  </xsd:complexType>
+
+  <xsd:element id="release" name="release" nillable="false"
+               type="tns:releaseType">
+    <xsd:annotation>
+      <xsd:documentation>
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:unique name="releaseDescriptionLangConstraint">
+      <xsd:selector xpath="tns:description" />
+      <xsd:field xpath="@lang" />
+    </xsd:unique>
+  </xsd:element>
+
+  <xsd:element id="changelog" name="changelog" nillable="false">
+    <xsd:annotation>
+      <xsd:documentation>
+        The changelog element is intended as the document root element. It
+        contains an overview element (identical in structure to the description
+        element, but named differently to prevent collision in XPath queries)
+        and one or more release blocks.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:complexType>
+      <xsd:sequence>
+        <xsd:element maxOccurs="unbounded" minOccurs="1" name="description"
+                     nillable="false" type="tns:descriptionType" />
+        <xsd:element maxOccurs="unbounded" minOccurs="0" name="information"
+                   type="tns:informationType" nillable="true" />
+        <xsd:element maxOccurs="1" minOccurs="0" name="vc-information"
+                     type="tns:informationType" nillable="true" />
+        <xsd:element maxOccurs="unbounded" minOccurs="1" ref="tns:release" />
+      </xsd:sequence>
+    </xsd:complexType>
+    <xsd:unique name="changelogDescriptionLangConstraint">
+      <xsd:selector xpath="tns:description" />
+      <xsd:field xpath="@lang" />
+    </xsd:unique>
+  </xsd:element>
+
+</xsd:schema>
+
diff --git a/xmlschemas.c b/xmlschemas.c
index 300f75f..3556756 100644
--- a/xmlschemas.c
+++ b/xmlschemas.c
@@ -1489,7 +1489,7 @@
 }
 
 /**
- * xmlSchemaGetCanonValueWhtsp:
+ * xmlSchemaGetCanonValueWhtspExt:
  * @val: the precomputed value
  * @retValue: the returned value
  * @ws: the whitespace type of the value
@@ -1501,14 +1501,14 @@
  *         API errors or if the value type is not supported yet.
  */
 static int
-xmlSchemaGetCanonValueWhtsp(const xmlChar *value,
+xmlSchemaGetCanonValueWhtspExt(const xmlChar *value,
 			    xmlSchemaValPtr val,
 			    xmlSchemaWhitespaceValueType ws,
 			    const xmlChar **retValue)
 {
     xmlSchemaValType valType;
 
-    if ((retValue == NULL) || (value == NULL) || (val == NULL))
+    if ((retValue == NULL) || ((value == NULL) && (val == NULL)))
 	return (-1);
     *retValue = NULL;
     valType = xmlSchemaGetValType(val);    
@@ -1572,7 +1572,7 @@
 	    if (facet->type != XML_SCHEMA_FACET_ENUMERATION)
 		continue;
 	    found = 1;
-	    res = xmlSchemaGetCanonValueWhtsp(facet->value, facet->val,
+	    res = xmlSchemaGetCanonValueWhtspExt(facet->value, facet->val,
 		ws, &value);
 	    if (res == -1) {
 		xmlSchemaVErr(NULL, NULL,
@@ -19673,6 +19673,45 @@
     return (resolved);
 }
 
+static const xmlChar *
+xmlSchemaFormatIDCKeySequence(xmlSchemaValidCtxtPtr ctxt,
+			      xmlChar **buf,
+			      xmlSchemaPSVIIDCKeyPtr *seq,
+			      int count)
+{
+    int i, res;
+    const xmlChar *value = NULL;
+
+    *buf = xmlStrdup(BAD_CAST "[");
+    for (i = 0; i < count; i++) {
+	*buf = xmlStrcat(*buf, BAD_CAST "'");
+	res = xmlSchemaGetCanonValueWhtsp(seq[i]->compValue, &value,
+	    (xmlSchemaWhitespaceValueType)
+		xmlSchemaGetWhiteSpaceFacetValue(seq[i]->type));
+	if (res == 0)
+	    *buf = xmlStrcat(*buf, value);
+	else {
+	    xmlSchemaVErr(ctxt, ctxt->node,
+		XML_SCHEMAV_INTERNAL,
+		"Internal error: xmlSchemaFormatIDCKeySequence, "
+		"failed to compute canonical value.\n",
+		NULL, NULL);
+	    *buf = xmlStrcat(*buf, BAD_CAST "???");
+	}
+	if (i < count -1)
+	    *buf = xmlStrcat(*buf, BAD_CAST "', ");
+	else
+	    *buf = xmlStrcat(*buf, BAD_CAST "'");
+	if (value != NULL) {
+	    xmlFree((xmlChar *) value);
+	    value = NULL;
+	}
+    }
+    *buf = xmlStrcat(*buf, BAD_CAST "]");
+
+    return (BAD_CAST *buf);
+}
+
 /**
  * xmlSchemaXPathProcessHistory:
  * @vctxt: the WXS validation context
@@ -19999,6 +20038,7 @@
 		    i++;
 		} while (i < bind->nbNodes);
 		if (i != bind->nbNodes) {
+		    xmlChar *str = NULL;
 		    /*   
 		    * TODO: Try to report the key-sequence.
 		    */
@@ -20006,8 +20046,10 @@
 			XML_SCHEMAV_CVC_IDC,
 			vctxt->nodeInfo,
 			(xmlSchemaTypePtr) idc,
-			"Duplicate key-sequence found", NULL, NULL);
-		    
+			"Duplicate key-sequence %s",
+			xmlSchemaFormatIDCKeySequence(vctxt, &str,
+			    (*keySeq), nbKeys), NULL);
+		    FREE_AND_NULL(str)
 		    goto selector_leave;
 		}
 	    }
@@ -20570,12 +20612,17 @@
 		    }
 		}
 		if (res == 0) {
+		    xmlChar *str = NULL;
 		    /* TODO: Report the key-sequence. */
 		    xmlSchemaVCustomErr(vctxt,
 			XML_SCHEMAV_CVC_IDC,
 			refbind->nodeTable[i]->node, 
 			(xmlSchemaTypePtr) refbind->definition,
-			"No matching key-sequence found", NULL);
+			"No match found for key reference %s",
+			xmlSchemaFormatIDCKeySequence(vctxt, &str,
+			 refbind->nodeTable[i]->keys,
+			 refbind->definition->nbFields));
+		    FREE_AND_NULL(str)
 		}
 	    }
 	}
diff --git a/xmlschemastypes.c b/xmlschemastypes.c
index 52dceaa..2b629bd 100644
--- a/xmlschemastypes.c
+++ b/xmlschemastypes.c
@@ -28,6 +28,9 @@
 #ifdef HAVE_MATH_H
 #include <math.h>
 #endif
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
 
 #define DEBUG
 
@@ -1550,7 +1553,7 @@
                 break;          /* exit loop */
             }
             /* no date designators found? */
-            if (++seq == 3)
+            if ((++seq == 3) || (seq == 6))
                 goto error;
         }
         cur++;
@@ -1907,25 +1910,36 @@
 		 * and note the position of any decimal point.
 		 */
 		len = 0;
-		while (len < 24) {
-		    if ((*cur >= '0') && (*cur <= '9')) {
-			*cptr++ = *cur;
-			len++;
-		    } else if (*cur == '.') {
-			if (dec != -1)
-			    goto return1;	/* multiple decimal points */
-			if (!len) {	/* num starts with '.' */
-			    *cptr++ = '0';
-			    len++;
-			}
-			dec = len++;
-		    } else
-			break;
+		/*
+		* Skip leading zeroes.
+		*/
+		while (*cur == '0')
 		    cur++;
+		if (*cur != 0) {
+		    while (len < 24) {
+			if ((*cur >= '0') && (*cur <= '9')) {
+			    *cptr++ = *cur++;
+			    len++;
+			} else if (*cur == '.') {
+			    if (dec != -1)
+				goto return1;	/* multiple decimal points */
+			    cur++;
+			    if ((*cur == 0) && (cur -1 == value))
+				goto return1;
+			    
+			    dec = len;
+			    while ((len < 24) && (*cur >= '0') &&
+				(*cur <= '9')) {
+				*cptr++ = *cur++;
+				len++;
+			    }
+			    break;
+			} else
+			    break;
+		    }
 		}
 		if (*cur != 0)
 		    goto return1;	/* error if any extraneous chars */
-
                 if (val != NULL) {
                     v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
                     if (v != NULL) {
@@ -1943,17 +1957,23 @@
 			/*
 		 	* Now evaluate the significant digits of the number
 		 	*/
-			xmlSchemaParseUInt((const xmlChar **)&cptr,
+			if (*cptr != 0) 
+			    xmlSchemaParseUInt((const xmlChar **)&cptr,
 					    &v->value.decimal.lo,
 					    &v->value.decimal.mi,
 					    &v->value.decimal.hi);
+			/*
+			* Set the total digits to 1 if a zero value.
+			*/
+			if (len == 0)
+			    len++;
                         v->value.decimal.sign = neg;
 			if (dec == -1) {
 			    v->value.decimal.frac = 0;
 			    v->value.decimal.total = len;
 			} else {
-			    v->value.decimal.frac = len - dec - 1;
-			    v->value.decimal.total = len - 1;
+			    v->value.decimal.frac = len - dec;
+			    v->value.decimal.total = len;
 			}
                         *val = v;
                     }
@@ -2675,6 +2695,8 @@
                 if (val != NULL) {
                     v = xmlSchemaNewValue(type->builtInType);
                     if (v != NULL) {
+			if (ret == 0)
+			    ret++;
                         v->value.decimal.lo = lo;
                         v->value.decimal.mi = mi;
                         v->value.decimal.hi = hi;
@@ -3364,7 +3386,8 @@
         return NULL;
 
     if (((dt->type != XML_SCHEMAS_TIME) &&
-         (dt->type != XML_SCHEMAS_DATETIME)) || (dt->value.date.tzo == 0))
+         (dt->type != XML_SCHEMAS_DATETIME) &&
+	 (dt->type != XML_SCHEMAS_DATE)) || (dt->value.date.tzo == 0))
         return xmlSchemaDupVal(dt);
 
     dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION);
@@ -4213,7 +4236,6 @@
         case XML_SCHEMAS_ID:
         case XML_SCHEMAS_IDREF:
         case XML_SCHEMAS_ENTITY:
-        case XML_SCHEMAS_NOTATION:
         case XML_SCHEMAS_ANYURI:
 	{
 	    const xmlChar *xv, *yv;
@@ -4286,9 +4308,11 @@
             return (-2);
 	}
         case XML_SCHEMAS_QNAME:
+	case XML_SCHEMAS_NOTATION:
 	    if ((x == NULL) || (y == NULL))
 		return(-2);
-            if (ytype == XML_SCHEMAS_QNAME) {
+            if ((ytype == XML_SCHEMAS_QNAME) ||
+		(ytype == XML_SCHEMAS_NOTATION)) {
 		if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) &&
 		    (xmlStrEqual(x->value.qname.uri, y->value.qname.uri)))
 		    return(0);
@@ -5003,18 +5027,104 @@
 	 value, val, ws));
 }
 
+#if 0
+#ifndef DBL_DIG
+#define DBL_DIG 16
+#endif
+#ifndef DBL_EPSILON
+#define DBL_EPSILON 1E-9
+#endif
+
+#define INTEGER_DIGITS DBL_DIG
+#define FRACTION_DIGITS (DBL_DIG + 1)
+#define EXPONENT_DIGITS (3 + 2)
+
+/**
+ * xmlXPathFormatNumber:
+ * @number:     number to format
+ * @buffer:     output buffer
+ * @buffersize: size of output buffer
+ *
+ * Convert the number into a string representation.
+ */
+static void
+xmlSchemaFormatFloat(double number, char buffer[], int buffersize)
+{
+    switch (xmlXPathIsInf(number)) {
+    case 1:
+	if (buffersize > (int)sizeof("INF"))
+	    snprintf(buffer, buffersize, "INF");
+	break;
+    case -1:
+	if (buffersize > (int)sizeof("-INF"))
+	    snprintf(buffer, buffersize, "-INF");
+	break;
+    default:
+	if (xmlXPathIsNaN(number)) {
+	    if (buffersize > (int)sizeof("NaN"))
+		snprintf(buffer, buffersize, "NaN");
+	} else if (number == 0) {
+	    snprintf(buffer, buffersize, "0.0E0");
+	} else {
+	    /* 3 is sign, decimal point, and terminating zero */
+	    char work[DBL_DIG + EXPONENT_DIGITS + 3];
+	    int integer_place, fraction_place;
+	    char *ptr;
+	    char *after_fraction;
+	    double absolute_value;
+	    int size;
+
+	    absolute_value = fabs(number);
+
+	    /*
+	     * Result is in work, and after_fraction points
+	     * just past the fractional part.
+	     * Use scientific notation 
+	    */
+	    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
+	    fraction_place = DBL_DIG - 1;
+	    snprintf(work, sizeof(work),"%*.*e",
+		integer_place, fraction_place, number);
+	    after_fraction = strchr(work + DBL_DIG, 'e');	    
+	    /* Remove fractional trailing zeroes */
+	    ptr = after_fraction;
+	    while (*(--ptr) == '0')
+		;
+	    if (*ptr != '.')
+	        ptr++;
+	    while ((*ptr++ = *after_fraction++) != 0);
+
+	    /* Finally copy result back to caller */
+	    size = strlen(work) + 1;
+	    if (size > buffersize) {
+		work[buffersize - 1] = 0;
+		size = buffersize;
+	    }
+	    memmove(buffer, work, size);
+	}
+	break;
+    }
+}
+#endif
+
 /**
  * xmlSchemaGetCanonValue:
  * @val: the precomputed value
  * @retValue: the returned value
  *
  * Get a the cononical lexical representation of the value.
- * The caller has to free the returned retValue.
+ * The caller has to FREE the returned retValue.
+ *
  * WARNING: Some value types are not supported yet, resulting
  * in a @retValue of "???".
+ * 
+ * TODO: XML Schema 1.0 does not define canonical representations
+ * for: duration, gYearMonth, gYear, gMonthDay, gMonth, gDay,
+ * anyURI, QName, NOTATION. This will be fixed in XML Schema 1.1.
  *
- * Returns 0 if the value could be built and -1 in case of
- *         API errors.
+ *
+ * Returns 0 if the value could be built, 1 if the value type is
+ * not supported yet and -1 in case of API errors.
  */
 int
 xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue)
@@ -5049,8 +5159,8 @@
 	case XML_SCHEMAS_ID:
 	case XML_SCHEMAS_IDREF:
 	case XML_SCHEMAS_ENTITY:
-	case XML_SCHEMAS_NOTATION:
-	case XML_SCHEMAS_ANYURI:	
+	case XML_SCHEMAS_NOTATION: /* Unclear */
+	case XML_SCHEMAS_ANYURI:   /* Unclear */
 	    if (val->value.str == NULL)
 		return (-1);
 	    *retValue = 
@@ -5060,9 +5170,7 @@
 		    BAD_CAST xmlStrdup((const xmlChar *) val->value.str);
 	    break;
 	case XML_SCHEMAS_QNAME:
-	    /*
-	    * TODO: What exactly to do with QNames?
-	    */
+	    /* TODO: Unclear in XML Schema 1.0. */
 	    if (val->value.qname.uri == NULL) {
 		*retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.qname.name);
 		return (0);
@@ -5076,14 +5184,392 @@
 		    BAD_CAST val->value.qname.uri);
 	    }
 	    break;
+	case XML_SCHEMAS_DECIMAL:
+	    /*
+	    * TODO: Lookout for a more simple implementation.
+	    */
+	    if ((val->value.decimal.total == 1) && 
+		(val->value.decimal.lo == 0)) {
+		*retValue = xmlStrdup(BAD_CAST "0.0");
+	    } else {
+		xmlSchemaValDecimal dec = val->value.decimal;
+		int bufsize;
+		char *buf = NULL, *offs;
+
+		/* Add room for the decimal point as well. */
+		bufsize = dec.total + 2;
+		if (dec.sign)
+		    bufsize++;
+		/* Add room for leading/trailing zero. */
+		if ((dec.frac == 0) || (dec.frac == dec.total))
+		    bufsize++;
+		buf = xmlMalloc(bufsize);
+		offs = buf;
+		if (dec.sign)
+		    *offs++ = '-';
+		if (dec.frac == dec.total) {
+		    *offs++ = '0';
+		    *offs++ = '.';
+		}
+		if (dec.hi != 0)
+		    snprintf(offs, bufsize - (offs - buf),
+			"%lu%lu%lu", dec.hi, dec.mi, dec.lo);
+		else if (dec.mi != 0)
+		    snprintf(offs, bufsize - (offs - buf),
+			"%lu%lu", dec.mi, dec.lo);
+		else
+		    snprintf(offs, bufsize - (offs - buf),
+			"%lu", dec.lo);
+			
+		if (dec.frac != 0) {
+		    if (dec.frac != dec.total) {
+			int diff = dec.total - dec.frac;
+			/*
+			* Insert the decimal point.
+			*/
+			memmove(offs + diff + 1, offs + diff, dec.frac +1);
+			offs[diff] = '.';
+		    } else {
+			unsigned int i = 0;
+			/*
+			* Insert missing zeroes behind the decimal point.
+			*/			
+			while (*(offs + i) != 0)
+			    i++;
+			if (i < dec.total) {
+			    memmove(offs + (dec.total - i), offs, i +1);
+			    memset(offs, '0', dec.total - i);
+			}
+		    }
+		} else {
+		    /*
+		    * Append decimal point and zero.
+		    */
+		    offs = buf + bufsize - 1;
+		    *offs-- = 0;
+		    *offs-- = '0';
+		    *offs-- = '.';
+		}
+		*retValue = BAD_CAST buf;
+	    }
+	    break;
+	case XML_SCHEMAS_INTEGER:
+        case XML_SCHEMAS_PINTEGER:
+        case XML_SCHEMAS_NPINTEGER:
+        case XML_SCHEMAS_NINTEGER:
+        case XML_SCHEMAS_NNINTEGER:
+	case XML_SCHEMAS_LONG:
+        case XML_SCHEMAS_BYTE:
+        case XML_SCHEMAS_SHORT:
+        case XML_SCHEMAS_INT:
+	case XML_SCHEMAS_UINT:
+        case XML_SCHEMAS_ULONG:
+        case XML_SCHEMAS_USHORT:
+        case XML_SCHEMAS_UBYTE:
+	    if ((val->value.decimal.total == 1) &&
+		(val->value.decimal.lo == 0))
+		*retValue = xmlStrdup(BAD_CAST "0");
+	    else {
+		xmlSchemaValDecimal dec = val->value.decimal;
+		int bufsize = dec.total + 1;
+
+		/* Add room for the decimal point as well. */
+		if (dec.sign)
+		    bufsize++;
+		*retValue = xmlMalloc(bufsize);
+		if (dec.hi != 0) {
+		    if (dec.sign)
+			snprintf((char *) *retValue, bufsize,
+			    "-%lu%lu%lu", dec.hi, dec.mi, dec.lo);
+		    else
+			snprintf((char *) *retValue, bufsize,
+			    "%lu%lu%lu", dec.hi, dec.mi, dec.lo);
+		} else if (dec.mi != 0) {
+		    if (dec.sign)
+			snprintf((char *) *retValue, bufsize,
+			    "-%lu%lu", dec.mi, dec.lo);
+		    else
+			snprintf((char *) *retValue, bufsize,
+			    "%lu%lu", dec.mi, dec.lo);
+		} else {
+		    if (dec.sign)
+			snprintf((char *) *retValue, bufsize, "-%lu", dec.lo);
+		    else
+			snprintf((char *) *retValue, bufsize, "%lu", dec.lo);
+		}
+	    }
+	    break;
+	case XML_SCHEMAS_BOOLEAN:
+	    if (val->value.b)
+		*retValue = BAD_CAST xmlStrdup(BAD_CAST "true");
+	    else
+		*retValue = BAD_CAST xmlStrdup(BAD_CAST "false");
+	    break;
+	case XML_SCHEMAS_DURATION: {
+		char buf[100];
+		unsigned long year;
+		unsigned long mon, day, hour = 0, min = 0;
+		double sec = 0, left;
+
+		/* TODO: Unclear in XML Schema 1.0 */
+		/*
+		* TODO: This results in a normalized output of the value
+		* - which is NOT conformant to the spec -
+		* since the exact values of each property are not
+		* recoverable. Think about extending the structure to
+		* provide a field for every property.
+		*/
+		year = (unsigned long) FQUOTIENT(labs(val->value.dur.mon), 12);
+		mon = labs(val->value.dur.mon) - 12 * year;
+
+		day = (unsigned long) FQUOTIENT(fabs(val->value.dur.sec), 86400);
+		left = fabs(val->value.dur.sec) - day * 86400;
+		if (left > 0) {
+		    hour = (unsigned long) FQUOTIENT(left, 3600);
+		    left = left - (hour * 3600);
+		    if (left > 0) {
+			min = (unsigned long) FQUOTIENT(left, 60);
+			sec = left - (min * 60);
+		    }
+		}
+		if ((val->value.dur.mon < 0) || (val->value.dur.sec < 0))
+		    snprintf(buf, 100, "P%luY%luM%luDT%luH%luM%.14gS",
+			year, mon, day, hour, min, sec);
+		else
+		    snprintf(buf, 100, "-P%luY%luM%luDT%luH%luM%.14gS",
+			year, mon, day, hour, min, sec);
+		*retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
+	    }
+	    break;
+	case XML_SCHEMAS_GYEAR: {
+		char buf[30];
+		/* TODO: Unclear in XML Schema 1.0 */
+		/* TODO: What to do with the timezone? */
+		snprintf(buf, 30, "%04ld", val->value.date.year);
+		*retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
+	    }
+	    break;
+	case XML_SCHEMAS_GMONTH: {
+		/* TODO: Unclear in XML Schema 1.0 */
+		/* TODO: What to do with the timezone? */
+		*retValue = xmlMalloc(5);
+		snprintf((char *) *retValue, 6, "--%02u",
+		    val->value.date.mon);
+	    }
+	    break;
+        case XML_SCHEMAS_GDAY: {
+		/* TODO: Unclear in XML Schema 1.0 */
+		/* TODO: What to do with the timezone? */
+		*retValue = xmlMalloc(6);
+		snprintf((char *) *retValue, 6, "---%02u",
+		    val->value.date.day);
+	    }
+	    break;        
+        case XML_SCHEMAS_GMONTHDAY: {
+		/* TODO: Unclear in XML Schema 1.0 */
+		/* TODO: What to do with the timezone? */
+		*retValue = xmlMalloc(8);
+		snprintf((char *) *retValue, 8, "--%02u-%02u",
+		    val->value.date.mon, val->value.date.day);
+	    }
+	    break;
+        case XML_SCHEMAS_GYEARMONTH: {
+		char buf[35];
+		/* TODO: Unclear in XML Schema 1.0 */
+		/* TODO: What to do with the timezone? */
+		if (val->value.date.year < 0)
+		    snprintf(buf, 35, "-%04ld-%02u",
+			labs(val->value.date.year), 
+			val->value.date.mon);
+		else
+		    snprintf(buf, 35, "%04ld-%02u",
+			val->value.date.year, val->value.date.mon);
+		*retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
+	    }
+	    break;		
+	case XML_SCHEMAS_TIME:
+	    {
+		char buf[30];
+
+		if (val->value.date.tz_flag) {
+		    xmlSchemaValPtr norm;
+
+		    norm = xmlSchemaDateNormalize(val, 0);
+		    if (norm == NULL)
+			return (-1);
+		    /* 
+		    * TODO: Check if "%.14g" is portable.		    
+		    */
+		    snprintf(buf, 30,
+			"%02u:%02u:%02.14gZ",
+			norm->value.date.hour,
+			norm->value.date.min,
+			norm->value.date.sec);
+		    xmlSchemaFreeValue(norm);
+		} else {
+		    snprintf(buf, 30,
+			"%02u:%02u:%02.14g",
+			val->value.date.hour,
+			val->value.date.min,
+			val->value.date.sec);
+		}
+		*retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
+	    }	    
+	    break;
+        case XML_SCHEMAS_DATE:
+	    {
+		char buf[30];
+
+		if (val->value.date.tz_flag) {
+		    xmlSchemaValPtr norm;
+
+		    norm = xmlSchemaDateNormalize(val, 0);
+		    if (norm == NULL)
+			return (-1);
+		    /*
+		    * TODO: Append the canonical value of the
+		    * recoverable timezone and not "Z".
+		    */
+		    snprintf(buf, 30,
+			"%04ld:%02u:%02uZ",
+			norm->value.date.year, norm->value.date.mon,
+			norm->value.date.day);
+		    xmlSchemaFreeValue(norm);
+		} else {
+		    snprintf(buf, 30,
+			"%04ld:%02u:%02u",
+			val->value.date.year, val->value.date.mon,
+			val->value.date.day);
+		}
+		*retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
+	    }	    
+	    break;
+        case XML_SCHEMAS_DATETIME:
+	    {
+		char buf[50];
+
+		if (val->value.date.tz_flag) {
+		    xmlSchemaValPtr norm;
+
+		    norm = xmlSchemaDateNormalize(val, 0);
+		    if (norm == NULL)
+			return (-1);
+		    /*
+		    * TODO: Check if "%.14g" is portable.
+		    */
+		    snprintf(buf, 50,
+			"%04ld:%02u:%02uT%02u:%02u:%02.14gZ",
+			norm->value.date.year, norm->value.date.mon,
+			norm->value.date.day, norm->value.date.hour,
+			norm->value.date.min, norm->value.date.sec);
+		    xmlSchemaFreeValue(norm);
+		} else {
+		    snprintf(buf, 50,
+			"%04ld:%02u:%02uT%02u:%02u:%02.14g",
+			val->value.date.year, val->value.date.mon,
+			val->value.date.day, val->value.date.hour,
+			val->value.date.min, val->value.date.sec);
+		}
+		*retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
+	    }
+	    break;
+	case XML_SCHEMAS_HEXBINARY:
+	    *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.hex.str);
+	    break;
+	case XML_SCHEMAS_BASE64BINARY:
+	    /*
+	    * TODO: Is the following spec piece implemented?:
+	    * SPEC: "Note: For some values the canonical form defined
+	    * above does not conform to [RFC 2045], which requires breaking
+	    * with linefeeds at appropriate intervals."
+	    */
+	    *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.base64.str);
+	    break;
+	case XML_SCHEMAS_FLOAT: {
+		char buf[30];		
+		/* 
+		* |m| < 16777216, -149 <= e <= 104.
+		* TODO: Handle, NaN, INF, -INF. The format is not
+		* yet conformant. The c type float does not cover
+		* the whole range.
+		*/
+		snprintf(buf, 30, "%01.14e", val->value.f);
+		*retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
+	    }
+	    break;
+	case XML_SCHEMAS_DOUBLE: {
+		char buf[40];
+		/* |m| < 9007199254740992, -1075 <= e <= 970 */
+		/*
+		* TODO: Handle, NaN, INF, -INF. The format is not
+		* yet conformant. The c type float does not cover
+		* the whole range.
+		*/
+		snprintf(buf, 40, "%01.14e", val->value.d);
+		*retValue = BAD_CAST xmlStrdup(BAD_CAST buf);
+	    }
+	    break;	
 	default:
 	    *retValue = BAD_CAST xmlStrdup(BAD_CAST "???");
-	    break;
+	    return (1);
     }
     return (0);
 }
 
 /**
+ * xmlSchemaGetCanonValueWhtsp:
+ * @val: the precomputed value
+ * @retValue: the returned value
+ * @ws: the whitespace type of the value
+ *
+ * Get a the cononical representation of the value.
+ * The caller has to free the returned @retValue.
+ *
+ * Returns 0 if the value could be built, 1 if the value type is
+ * not supported yet and -1 in case of API errors.
+ */
+int
+xmlSchemaGetCanonValueWhtsp(xmlSchemaValPtr val,
+			    const xmlChar **retValue,
+			    xmlSchemaWhitespaceValueType ws)
+{
+    if ((retValue == NULL) || (val == NULL))
+	return (-1);
+    if ((ws == XML_SCHEMA_WHITESPACE_UNKNOWN) ||
+	(ws > XML_SCHEMA_WHITESPACE_COLLAPSE))
+	return (-1);
+
+    *retValue = NULL;
+    switch (val->type) {
+	case XML_SCHEMAS_STRING:
+	    if (val->value.str == NULL)
+		*retValue = BAD_CAST xmlStrdup(BAD_CAST "");
+	    else if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
+		*retValue = xmlSchemaCollapseString(val->value.str);
+	    else if (ws == XML_SCHEMA_WHITESPACE_REPLACE)
+		*retValue = xmlSchemaWhiteSpaceReplace(val->value.str);
+	    if ((*retValue) == NULL)
+		*retValue = BAD_CAST xmlStrdup(val->value.str);
+	    break;
+	case XML_SCHEMAS_NORMSTRING:
+	    if (val->value.str == NULL)
+		*retValue = BAD_CAST xmlStrdup(BAD_CAST "");
+	    else {
+		if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
+		    *retValue = xmlSchemaCollapseString(val->value.str);
+		else
+		    *retValue = xmlSchemaWhiteSpaceReplace(val->value.str);
+		if ((*retValue) == NULL)
+		    *retValue = BAD_CAST xmlStrdup(val->value.str);
+	    }
+	    break;
+	default:
+	    return (xmlSchemaGetCanonValue(val, retValue));
+    }    
+    return (0);
+}
+
+/**
  * xmlSchemaGetValType:
  * @val: a schemas value
  *