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:
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user