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.
This commit is contained in:
Kasimier T. Buchcik 2005-04-18 10:57:04 +00:00
parent d6e347e865
commit c872afbd82
6 changed files with 853 additions and 38 deletions

View File

@ -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

View File

@ -111,6 +111,10 @@ XMLPUBFUN int XMLCALL
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);

View File

@ -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>

View File

@ -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>

View File

@ -1489,7 +1489,7 @@ xmlSchemaPRequestItemDes(xmlChar **buf,
}
/**
* xmlSchemaGetCanonValueWhtsp:
* xmlSchemaGetCanonValueWhtspExt:
* @val: the precomputed value
* @retValue: the returned value
* @ws: the whitespace type of the value
@ -1501,14 +1501,14 @@ xmlSchemaPRequestItemDes(xmlChar **buf,
* 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 @@ xmlSchemaFormatFacetEnumSet(xmlChar **buf, xmlSchemaTypePtr type)
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 @@ next_sto:
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 @@ create_key:
i++;
} while (i < bind->nbNodes);
if (i != bind->nbNodes) {
xmlChar *str = NULL;
/*
* TODO: Try to report the key-sequence.
*/
@ -20006,8 +20046,10 @@ create_key:
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 @@ xmlSchemaCheckCVCIDCKeyRef(xmlSchemaValidCtxtPtr vctxt)
}
}
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)
}
}
}

View File

@ -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 @@ xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
break; /* exit loop */
}
/* no date designators found? */
if (++seq == 3)
if ((++seq == 3) || (seq == 6))
goto error;
}
cur++;
@ -1907,25 +1910,36 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
* 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 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
/*
* 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 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
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 @@ xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset)
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 @@ xmlSchemaCompareValuesInternal(xmlSchemaValType xtype,
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 @@ xmlSchemaCompareValuesInternal(xmlSchemaValType xtype,
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 @@ xmlSchemaValidateFacetWhtsp(xmlSchemaFacetPtr facet,
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 "???".
*
* Returns 0 if the value could be built and -1 in case of
* API errors.
* 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, 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 @@ xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue)
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 @@ xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue)
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,9 +5184,387 @@ xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue)
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 "???");
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);
}