1
0
mirror of https://gitlab.gnome.org/GNOME/libxslt synced 2025-11-06 23:49:25 +03:00

reworked internal representation of tokenized number format and

* libxslt/numbers.c: reworked internal representation of
	  tokenized number format and parsing/tokenization. This fixes
	  many bugs regarding separator and default tokens.
	* tests/REC/test-7.7-3.out: the fix changes the output of this
	  test. It now complies to the XSLT spec (wow! ;o)
This commit is contained in:
Thomas Broyer
2001-10-17 01:08:24 +00:00
parent e74d9fef32
commit 0c4d3048d4
3 changed files with 125 additions and 84 deletions

View File

@@ -1,3 +1,11 @@
Wed Oct 17 02:46:55 CEST 2001 Thomas Broyer <tbroyer@ltgt.net>
* libxslt/numbers.c: reworked internal representation of
tokenized number format and parsing/tokenization. This fixes
many bugs regarding separator and default tokens.
* tests/REC/test-7.7-3.out: the fix changes the output of this
test. It now complies to the XSLT spec (wow! ;o)
Tue Oct 16 11:25:15 CEST 2001 Daniel Veillard <daniel@veillard.com> Tue Oct 16 11:25:15 CEST 2001 Daniel Veillard <daniel@veillard.com>
* xsltproc/Makefile.am configure.in config.h.in: trying to * xsltproc/Makefile.am configure.in config.h.in: trying to

View File

@@ -32,15 +32,31 @@
#define SYMBOL_QUOTE ((xmlChar)'\'') #define SYMBOL_QUOTE ((xmlChar)'\'')
typedef struct _xsltNumberFormatToken { #define DEFAULT_TOKEN (xmlChar)'0'
#define DEFAULT_SEPARATOR "."
#define MAX_TOKENS 1024
typedef struct _xsltFormatToken xsltFormatToken;
typedef xsltFormatToken *xsltFormatTokenPtr;
struct _xsltFormatToken {
xmlChar *separator;
xmlChar token; xmlChar token;
int width; int width;
xmlChar *filling; };
} xsltNumberFormatToken, *xsltNumberFormatTokenPtr;
typedef struct _xsltFormat xsltFormat;
typedef xsltFormat *xsltFormatPtr;
struct _xsltFormat {
xmlChar *start;
xsltFormatToken tokens[MAX_TOKENS];
int nTokens;
xmlChar *end;
};
static char alpha_upper_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; static char alpha_upper_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static char alpha_lower_list[] = "abcdefghijklmnopqrstuvwxyz"; static char alpha_lower_list[] = "abcdefghijklmnopqrstuvwxyz";
static xsltNumberFormatToken default_token; static xsltFormatToken default_token;
/************************************************************************ /************************************************************************
@@ -194,22 +210,25 @@ xsltNumberFormatRoman(xmlBufferPtr buffer,
} }
} }
static int static void
xsltNumberFormatTokenize(xmlChar *format, xsltNumberFormatTokenize(xmlChar *format,
xsltNumberFormatTokenPtr array, xsltFormatPtr tokens)
int array_max)
{ {
int index = 0; int index = 0;
int cnt;
int j; int j;
default_token.token = (xmlChar)'0'; default_token.token = DEFAULT_TOKEN;
default_token.width = 1; default_token.width = 1;
default_token.filling = BAD_CAST("."); default_token.separator = BAD_CAST(DEFAULT_SEPARATOR);
tokens->start = NULL;
tokens->tokens[0].separator = NULL;
tokens->end = NULL;
/* /*
* Parse initial non-alphanumeric token * Insert initial non-alphanumeric token.
* Always use an empty token for that * There is always such a token in the list, even if NULL
*/ */
while (! (IS_LETTER(format[index]) || IS_DIGIT(format[index]))) { while (! (IS_LETTER(format[index]) || IS_DIGIT(format[index]))) {
if (format[index] == 0) if (format[index] == 0)
@@ -217,35 +236,45 @@ xsltNumberFormatTokenize(xmlChar *format,
index++; index++;
} }
if (index > 0) if (index > 0)
array[0].filling = xmlStrndup(format, index); tokens->start = xmlStrndup(format, index);
else
array[0].filling = NULL;
for (cnt = 1; cnt < array_max; cnt++) {
if (format[index] == 0) { for (tokens->nTokens = 0; tokens->nTokens < MAX_TOKENS;
tokens->nTokens++) {
if (format[index] == 0)
break; /* for */ break; /* for */
} else if (IS_DIGIT_ONE(format[index]) ||
/*
* separator has already been parsed (except for the first
* number) in tokens->end, recover it.
*/
if (tokens->nTokens > 0) {
tokens->tokens[tokens->nTokens].separator = tokens->end;
tokens->end = NULL;
}
if (IS_DIGIT_ONE(format[index]) ||
IS_DIGIT_ZERO(format[index])) { IS_DIGIT_ZERO(format[index])) {
array[cnt].width = 1; tokens->tokens[tokens->nTokens].width = 1;
while (IS_DIGIT_ZERO(format[index])) { while (IS_DIGIT_ZERO(format[index])) {
array[cnt].width++; tokens->tokens[tokens->nTokens].width++;
index++; index++;
} }
if (IS_DIGIT_ONE(format[index])) { if (IS_DIGIT_ONE(format[index])) {
array[cnt].token = format[index] - 1; tokens->tokens[tokens->nTokens].token = format[index] - 1;
index++; index++;
} }
} else if (format[index] == (xmlChar)'A') { } else if (format[index] == (xmlChar)'A') {
array[cnt].token = format[index]; tokens->tokens[tokens->nTokens].token = format[index];
index++; index++;
} else if (format[index] == (xmlChar)'a') { } else if (format[index] == (xmlChar)'a') {
array[cnt].token = format[index]; tokens->tokens[tokens->nTokens].token = format[index];
index++; index++;
} else if (format[index] == (xmlChar)'I') { } else if (format[index] == (xmlChar)'I') {
array[cnt].token = format[index]; tokens->tokens[tokens->nTokens].token = format[index];
index++; index++;
} else if (format[index] == (xmlChar)'i') { } else if (format[index] == (xmlChar)'i') {
array[cnt].token = format[index]; tokens->tokens[tokens->nTokens].token = format[index];
index++; index++;
} else { } else {
/* XSLT section 7.7 /* XSLT section 7.7
@@ -254,9 +283,8 @@ xsltNumberFormatTokenize(xmlChar *format,
* not support a numbering sequence that starts with that * not support a numbering sequence that starts with that
* token, it must use a format token of 1." * token, it must use a format token of 1."
*/ */
array[cnt].token = (xmlChar)'0'; tokens->tokens[tokens->nTokens].token = (xmlChar)'0';
array[cnt].width = 1; tokens->tokens[tokens->nTokens].width = 1;
index++;
} }
/* /*
* Skip over remaining alphanumeric characters from the Nd * Skip over remaining alphanumeric characters from the Nd
@@ -269,8 +297,9 @@ xsltNumberFormatTokenize(xmlChar *format,
*/ */
while (IS_LETTER(format[index]) || IS_DIGIT(format[index])) while (IS_LETTER(format[index]) || IS_DIGIT(format[index]))
index++; index++;
/* /*
* Insert non-alphanumeric separator. * Insert temporary non-alphanumeric final tooken.
*/ */
j = index; j = index;
while (! (IS_LETTER(format[index]) || IS_DIGIT(format[index]))) { while (! (IS_LETTER(format[index]) || IS_DIGIT(format[index]))) {
@@ -279,47 +308,51 @@ xsltNumberFormatTokenize(xmlChar *format,
index++; index++;
} }
if (index > j) if (index > j)
array[cnt].filling = xmlStrndup(&format[j], index - j); tokens->end = xmlStrndup(&format[j], index - j);
else
array[cnt].filling = NULL;
} }
return cnt;
} }
static void static void
xsltNumberFormatInsertNumbers(xsltNumberDataPtr data, xsltNumberFormatInsertNumbers(xsltNumberDataPtr data,
double *numbers, double *numbers,
int numbers_max, int numbers_max,
xsltNumberFormatToken (*array)[], xsltFormatPtr tokens,
int array_max,
xmlBufferPtr buffer) xmlBufferPtr buffer)
{ {
int i = 0; int i = 0;
int minmax;
double number; double number;
xsltNumberFormatTokenPtr token; xsltFormatTokenPtr token;
int is_last_default_token = 0;
minmax = (array_max >= numbers_max) ? numbers_max : array_max;
/* /*
* Handle initial non-alphanumeric token * Handle initial non-alphanumeric token
*/ */
token = &(*array)[0]; if (tokens->start != NULL)
if (token->filling != NULL) xmlBufferCat(buffer, tokens->start);
xmlBufferCat(buffer, token->filling);
for (i = 0; i < numbers_max; i++) { for (i = 0; i < numbers_max; i++) {
/* Insert number */ /* Insert number */
number = numbers[(numbers_max - 1) - i]; number = numbers[(numbers_max - 1) - i];
if (i + 1 < array_max) { if (i < tokens->nTokens) {
token = &(*array)[i + 1]; /* The "n"th format token will be used to format the "n"th
} else if (array_max > 1) { * number in the list */
token = &(*array)[array_max - 1]; token = &(tokens->tokens[i]);
} else if (tokens->nTokens > 0) {
/* If there are more numbers than format tokens, then the
* last format token will be used to format the remaining
* numbers. */
token = &(tokens->tokens[tokens->nTokens - 1]);
} else { } else {
/* If there are no format tokens, then a format token of
* 1 is used to format all numbers. */
token = &default_token; token = &default_token;
is_last_default_token = (i >= numbers_max - 1); }
/* Print separator, except for the first number */
if (i > 0) {
if (token->separator != NULL)
xmlBufferCat(buffer, token->separator);
else
xmlBufferCCat(buffer, DEFAULT_SEPARATOR);
} }
switch (xmlXPathIsInf(number)) { switch (xmlXPathIsInf(number)) {
@@ -373,10 +406,14 @@ xsltNumberFormatInsertNumbers(xsltNumberDataPtr data,
} }
} }
if ((token->filling != NULL) && !is_last_default_token)
xmlBufferCat(buffer, token->filling);
} }
/*
* Handle final non-alphanumeric token
*/
if (tokens->end != NULL)
xmlBufferCat(buffer, tokens->end);
} }
static int static int
@@ -385,7 +422,6 @@ xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context,
xmlChar *count, xmlChar *count,
xmlChar *from, xmlChar *from,
double *array, double *array,
int max ATTRIBUTE_UNUSED,
xmlDocPtr doc, xmlDocPtr doc,
xmlNodePtr elem) xmlNodePtr elem)
{ {
@@ -574,9 +610,8 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
xmlBufferPtr output = NULL; xmlBufferPtr output = NULL;
xmlNodePtr copy = NULL; xmlNodePtr copy = NULL;
int amount, i; int amount, i;
int array_amount;
double number; double number;
xsltNumberFormatToken array[1024]; xsltFormat tokens;
if ((data->format == NULL) && (data->has_format != 0)) { if ((data->format == NULL) && (data->has_format != 0)) {
data->format = xsltEvalAttrValueTemplate(ctxt, data->node, data->format = xsltEvalAttrValueTemplate(ctxt, data->node,
@@ -591,9 +626,7 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
if (output == NULL) if (output == NULL)
goto XSLT_NUMBER_FORMAT_END; goto XSLT_NUMBER_FORMAT_END;
array_amount = xsltNumberFormatTokenize(data->format, xsltNumberFormatTokenize(data->format, &tokens);
array,
sizeof(array)/sizeof(array[0]));
/* /*
* Evaluate the XPath expression to find the value(s) * Evaluate the XPath expression to find the value(s)
@@ -607,8 +640,7 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
xsltNumberFormatInsertNumbers(data, xsltNumberFormatInsertNumbers(data,
&number, &number,
1, 1,
&array, &tokens,
array_amount,
output); output);
} }
@@ -627,8 +659,7 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
xsltNumberFormatInsertNumbers(data, xsltNumberFormatInsertNumbers(data,
&number, &number,
1, 1,
&array, &tokens,
array_amount,
output); output);
} }
} else if (xmlStrEqual(data->level, (const xmlChar *) "multiple")) { } else if (xmlStrEqual(data->level, (const xmlChar *) "multiple")) {
@@ -646,8 +677,7 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
xsltNumberFormatInsertNumbers(data, xsltNumberFormatInsertNumbers(data,
numarray, numarray,
amount, amount,
&array, &tokens,
array_amount,
output); output);
} }
} else if (xmlStrEqual(data->level, (const xmlChar *) "any")) { } else if (xmlStrEqual(data->level, (const xmlChar *) "any")) {
@@ -656,15 +686,13 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
data->count, data->count,
data->from, data->from,
&number, &number,
1,
data->doc, data->doc,
data->node); data->node);
if (amount > 0) { if (amount > 0) {
xsltNumberFormatInsertNumbers(data, xsltNumberFormatInsertNumbers(data,
&number, &number,
1, 1,
&array, &tokens,
array_amount,
output); output);
} }
} }
@@ -674,9 +702,14 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
if (copy != NULL) { if (copy != NULL) {
xmlAddChild(ctxt->insert, copy); xmlAddChild(ctxt->insert, copy);
} }
for (i = 0;i < array_amount;i++) {
if (array[i].filling != NULL) if (tokens.start != NULL)
xmlFree(array[i].filling); xmlFree(tokens.start);
if (tokens.end != NULL)
xmlFree(tokens.end);
for (i = 0;i < tokens.nTokens;i++) {
if (tokens.tokens[i].separator != NULL)
xmlFree(tokens.tokens[i].separator);
} }
XSLT_NUMBER_FORMAT_END: XSLT_NUMBER_FORMAT_END:

View File

@@ -1,29 +1,29 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">1.First Chapter</fo:block> <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">1 First Chapter</fo:block>
Here is some text. Here is some text.
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">1.1 First Chapter, First Section</fo:block> <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">1.1 First Chapter, First Section</fo:block>
More text here. More text here.
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">1.1 1 First Chapter, First Section, First Subsection</fo:block> <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">1.1.1 First Chapter, First Section, First Subsection</fo:block>
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">1.1 2 First Chapter, First Section, Second Subsection</fo:block> <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">1.1.2 First Chapter, First Section, Second Subsection</fo:block>
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">2.Second Chapter</fo:block> <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">2 Second Chapter</fo:block>
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">A.First Appendix</fo:block> <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">A First Appendix</fo:block>
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">A.1 First Appendix, First Section</fo:block> <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">A.1 First Appendix, First Section</fo:block>
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">B.Second Appendix</fo:block> <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">B Second Appendix</fo:block>