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
*