2
* Copyright 1999-2004 The Apache Software Foundation.
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
17
* $Id: NumeratorFormatter.java,v 1.8 2004/02/16 20:41:29 minchau Exp $
19
package org.apache.xalan.transformer;
21
import java.util.Locale;
22
import java.util.NoSuchElementException;
24
import org.w3c.dom.Element;
27
* Converts enumerated numbers into strings, using the XSL conversion attributes.
28
* Having this in a class helps avoid being forced to extract the attributes repeatedly.
31
class NumeratorFormatter
34
/** The owning xsl:number element. */
35
protected Element m_xslNumberElement;
37
/** An instance of a Tokenizer */
38
NumberFormatStringTokenizer m_formatTokenizer;
40
/** Locale we need to format in */
43
/** An instance of a NumberFormat */
44
java.text.NumberFormat m_formatter;
46
/** An instance of a transformer */
47
TransformerImpl m_processor;
50
* Table to help in converting decimals to roman numerals.
51
* @see org.apache.xalan.transformer.DecimalToRoman
53
private final static DecimalToRoman m_romanConvertTable[] = {
54
new DecimalToRoman(1000, "M", 900, "CM"),
55
new DecimalToRoman(500, "D", 400, "CD"),
56
new DecimalToRoman(100L, "C", 90L, "XC"),
57
new DecimalToRoman(50L, "L", 40L, "XL"),
58
new DecimalToRoman(10L, "X", 9L, "IX"),
59
new DecimalToRoman(5L, "V", 4L, "IV"),
60
new DecimalToRoman(1L, "I", 1L, "I") };
63
* Chars for converting integers into alpha counts.
64
* @see TransformerImpl#int2alphaCount
66
private final static char[] m_alphaCountTable = { 'Z', // z for zero
67
'A', 'B', 'C', 'D', 'E',
68
'F', 'G', 'H', 'I', 'J',
69
'K', 'L', 'M', 'N', 'O',
70
'P', 'Q', 'R', 'S', 'T',
71
'U', 'V', 'W', 'X', 'Y' };
74
* Construct a NumeratorFormatter using an element
75
* that contains XSL number conversion attributes -
76
* format, letter-value, xml:lang, digit-group-sep,
77
* n-digits-per-group, and sequence-src.
79
* @param xslNumberElement The given xsl:number element
80
* @param processor a non-null transformer instance
82
NumeratorFormatter(Element xslNumberElement, TransformerImpl processor)
84
m_xslNumberElement = xslNumberElement;
85
m_processor = processor;
86
} // end NumeratorFormatter(Element) constructor
89
* Convert a long integer into alphabetic counting, in other words
90
* count using the sequence A B C ... Z AA AB AC.... etc.
92
* @param val Value to convert -- must be greater than zero.
93
* @param table a table containing one character for each digit in the radix
94
* @return String representing alpha count of number.
95
* @see org.apache.xalan.transformer.DecimalToRoman
97
* Note that the radix of the conversion is inferred from the size
100
protected String int2alphaCount(int val, char[] table)
103
int radix = table.length;
105
// Create a buffer to hold the result
106
// TODO: size of the table can be detereined by computing
107
// logs of the radix. For now, we fake it.
108
char buf[] = new char[100];
110
// next character to set in the buffer
111
int charPos = buf.length - 1; // work backward through buf[]
113
// index in table of the last character that we stored
114
int lookupIndex = 1; // start off with anything other than zero to make correction work
118
// Correction can take on exactly two values:
120
// 0 if the next character is to be emitted is usual
123
// if the next char to be emitted should be one less than
126
// For example, consider radix 10, where 1="A" and 10="J"
128
// In this scheme, we count: A, B, C ... H, I, J (not A0 and certainly
131
// So, how do we keep from emitting AJ for 10? After correctly emitting the
132
// J, lookupIndex is zero. We now compute a correction number of 9 (radix-1).
133
// In the following line, we'll compute (val+correction) % radix, which is,
134
// (val+9)/10. By this time, val is 1, so we compute (1+9) % 10, which
135
// is 10 % 10 or zero. So, we'll prepare to emit "JJ", but then we'll
136
// later suppress the leading J as representing zero (in the mod system,
137
// it can represent either 10 or zero). In summary, the correction value of
138
// "radix-1" acts like "-1" when run through the mod operator, but with the
139
// desireable characteristic that it never produces a negative number.
142
// TODO: throw error on out of range input
146
// most of the correction calculation is explained above, the reason for the
147
// term after the "|| " is that it correctly propagates carries across
150
((lookupIndex == 0) || (correction != 0 && lookupIndex == radix - 1))
153
// index in "table" of the next char to emit
154
lookupIndex = (val + correction) % radix;
156
// shift input by one "column"
159
// if the next value we'd put out would be a leading zero, we're done.
160
if (lookupIndex == 0 && val == 0)
163
// put out the next character of output
164
buf[charPos--] = table[lookupIndex];
168
return new String(buf, charPos + 1, (buf.length - charPos - 1));
172
* Convert a long integer into roman numerals.
173
* @param val Value to convert.
174
* @param prefixesAreOK true_ to enable prefix notation (e.g. 4 = "IV"),
175
* false_ to disable prefix notation (e.g. 4 = "IIII").
176
* @return Roman numeral string.
177
* @see DecimalToRoman
178
* @see m_romanConvertTable
180
String long2roman(long val, boolean prefixesAreOK)
185
return "#E(" + val + ")";
195
while (val >= m_romanConvertTable[place].m_postValue)
197
roman += m_romanConvertTable[place].m_postLetter;
198
val -= m_romanConvertTable[place].m_postValue;
203
if (val >= m_romanConvertTable[place].m_preValue)
205
roman += m_romanConvertTable[place].m_preLetter;
206
val -= m_romanConvertTable[place].m_preValue;
223
* This class returns tokens using non-alphanumberic
224
* characters as delimiters.
226
class NumberFormatStringTokenizer
229
/** Field holding the current position in the string */
230
private int currentPosition;
232
/** The total length of the string */
233
private int maxPosition;
235
/** The string to tokenize */
239
* Construct a NumberFormatStringTokenizer.
241
* @param str The string to tokenize
243
NumberFormatStringTokenizer(String str)
246
maxPosition = str.length();
250
* Reset tokenizer so that nextToken() starts from the beginning.
259
* Returns the next token from this string tokenizer.
261
* @return the next token from this string tokenizer.
262
* @throws NoSuchElementException if there are no more tokens in this
263
* tokenizer's string.
268
if (currentPosition >= maxPosition)
270
throw new NoSuchElementException();
273
int start = currentPosition;
275
while ((currentPosition < maxPosition)
276
&& Character.isLetterOrDigit(str.charAt(currentPosition)))
281
if ((start == currentPosition)
282
&& (!Character.isLetterOrDigit(str.charAt(currentPosition))))
287
return str.substring(start, currentPosition);
291
* Tells if <code>nextToken</code> will throw an exception * if it is called.
293
* @return true if <code>nextToken</code> can be called * without throwing an exception.
295
boolean hasMoreTokens()
297
return (currentPosition >= maxPosition) ? false : true;
301
* Calculates the number of times that this tokenizer's
302
* <code>nextToken</code> method can be called before it generates an
305
* @return the number of tokens remaining in the string using the current
307
* @see java.util.StringTokenizer#nextToken()
313
int currpos = currentPosition;
315
while (currpos < maxPosition)
319
while ((currpos < maxPosition)
320
&& Character.isLetterOrDigit(str.charAt(currpos)))
325
if ((start == currpos)
326
&& (Character.isLetterOrDigit(str.charAt(currpos)) == false))
336
} // end NumberFormatStringTokenizer
2
* Licensed to the Apache Software Foundation (ASF) under one
3
* or more contributor license agreements. See the NOTICE file
4
* distributed with this work for additional information
5
* regarding copyright ownership. The ASF licenses this file
6
* to you under the Apache License, Version 2.0 (the "License");
7
* you may not use this file except in compliance with the License.
8
* You may obtain a copy of the License at
10
* http://www.apache.org/licenses/LICENSE-2.0
12
* Unless required by applicable law or agreed to in writing, software
13
* distributed under the License is distributed on an "AS IS" BASIS,
14
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
* See the License for the specific language governing permissions and
16
* limitations under the License.
19
* $Id: NumeratorFormatter.java 468645 2006-10-28 06:57:24Z minchau $
21
package org.apache.xalan.transformer;
23
import java.util.Locale;
24
import java.util.NoSuchElementException;
26
import org.w3c.dom.Element;
29
* Converts enumerated numbers into strings, using the XSL conversion attributes.
30
* Having this in a class helps avoid being forced to extract the attributes repeatedly.
33
class NumeratorFormatter
36
/** The owning xsl:number element. */
37
protected Element m_xslNumberElement;
39
/** An instance of a Tokenizer */
40
NumberFormatStringTokenizer m_formatTokenizer;
42
/** Locale we need to format in */
45
/** An instance of a NumberFormat */
46
java.text.NumberFormat m_formatter;
48
/** An instance of a transformer */
49
TransformerImpl m_processor;
52
* Table to help in converting decimals to roman numerals.
53
* @see org.apache.xalan.transformer.DecimalToRoman
55
private final static DecimalToRoman m_romanConvertTable[] = {
56
new DecimalToRoman(1000, "M", 900, "CM"),
57
new DecimalToRoman(500, "D", 400, "CD"),
58
new DecimalToRoman(100L, "C", 90L, "XC"),
59
new DecimalToRoman(50L, "L", 40L, "XL"),
60
new DecimalToRoman(10L, "X", 9L, "IX"),
61
new DecimalToRoman(5L, "V", 4L, "IV"),
62
new DecimalToRoman(1L, "I", 1L, "I") };
65
* Chars for converting integers into alpha counts.
66
* @see TransformerImpl#int2alphaCount
68
private final static char[] m_alphaCountTable = { 'Z', // z for zero
69
'A', 'B', 'C', 'D', 'E',
70
'F', 'G', 'H', 'I', 'J',
71
'K', 'L', 'M', 'N', 'O',
72
'P', 'Q', 'R', 'S', 'T',
73
'U', 'V', 'W', 'X', 'Y' };
76
* Construct a NumeratorFormatter using an element
77
* that contains XSL number conversion attributes -
78
* format, letter-value, xml:lang, digit-group-sep,
79
* n-digits-per-group, and sequence-src.
81
* @param xslNumberElement The given xsl:number element
82
* @param processor a non-null transformer instance
84
NumeratorFormatter(Element xslNumberElement, TransformerImpl processor)
86
m_xslNumberElement = xslNumberElement;
87
m_processor = processor;
88
} // end NumeratorFormatter(Element) constructor
91
* Convert a long integer into alphabetic counting, in other words
92
* count using the sequence A B C ... Z AA AB AC.... etc.
94
* @param val Value to convert -- must be greater than zero.
95
* @param table a table containing one character for each digit in the radix
96
* @return String representing alpha count of number.
97
* @see org.apache.xalan.transformer.DecimalToRoman
99
* Note that the radix of the conversion is inferred from the size
102
protected String int2alphaCount(int val, char[] table)
105
int radix = table.length;
107
// Create a buffer to hold the result
108
// TODO: size of the table can be detereined by computing
109
// logs of the radix. For now, we fake it.
110
char buf[] = new char[100];
112
// next character to set in the buffer
113
int charPos = buf.length - 1; // work backward through buf[]
115
// index in table of the last character that we stored
116
int lookupIndex = 1; // start off with anything other than zero to make correction work
120
// Correction can take on exactly two values:
122
// 0 if the next character is to be emitted is usual
125
// if the next char to be emitted should be one less than
128
// For example, consider radix 10, where 1="A" and 10="J"
130
// In this scheme, we count: A, B, C ... H, I, J (not A0 and certainly
133
// So, how do we keep from emitting AJ for 10? After correctly emitting the
134
// J, lookupIndex is zero. We now compute a correction number of 9 (radix-1).
135
// In the following line, we'll compute (val+correction) % radix, which is,
136
// (val+9)/10. By this time, val is 1, so we compute (1+9) % 10, which
137
// is 10 % 10 or zero. So, we'll prepare to emit "JJ", but then we'll
138
// later suppress the leading J as representing zero (in the mod system,
139
// it can represent either 10 or zero). In summary, the correction value of
140
// "radix-1" acts like "-1" when run through the mod operator, but with the
141
// desireable characteristic that it never produces a negative number.
144
// TODO: throw error on out of range input
148
// most of the correction calculation is explained above, the reason for the
149
// term after the "|| " is that it correctly propagates carries across
152
((lookupIndex == 0) || (correction != 0 && lookupIndex == radix - 1))
155
// index in "table" of the next char to emit
156
lookupIndex = (val + correction) % radix;
158
// shift input by one "column"
161
// if the next value we'd put out would be a leading zero, we're done.
162
if (lookupIndex == 0 && val == 0)
165
// put out the next character of output
166
buf[charPos--] = table[lookupIndex];
170
return new String(buf, charPos + 1, (buf.length - charPos - 1));
174
* Convert a long integer into roman numerals.
175
* @param val Value to convert.
176
* @param prefixesAreOK true_ to enable prefix notation (e.g. 4 = "IV"),
177
* false_ to disable prefix notation (e.g. 4 = "IIII").
178
* @return Roman numeral string.
179
* @see DecimalToRoman
180
* @see m_romanConvertTable
182
String long2roman(long val, boolean prefixesAreOK)
187
return "#E(" + val + ")";
197
while (val >= m_romanConvertTable[place].m_postValue)
199
roman += m_romanConvertTable[place].m_postLetter;
200
val -= m_romanConvertTable[place].m_postValue;
205
if (val >= m_romanConvertTable[place].m_preValue)
207
roman += m_romanConvertTable[place].m_preLetter;
208
val -= m_romanConvertTable[place].m_preValue;
225
* This class returns tokens using non-alphanumberic
226
* characters as delimiters.
228
class NumberFormatStringTokenizer
231
/** Field holding the current position in the string */
232
private int currentPosition;
234
/** The total length of the string */
235
private int maxPosition;
237
/** The string to tokenize */
241
* Construct a NumberFormatStringTokenizer.
243
* @param str The string to tokenize
245
NumberFormatStringTokenizer(String str)
248
maxPosition = str.length();
252
* Reset tokenizer so that nextToken() starts from the beginning.
261
* Returns the next token from this string tokenizer.
263
* @return the next token from this string tokenizer.
264
* @throws NoSuchElementException if there are no more tokens in this
265
* tokenizer's string.
270
if (currentPosition >= maxPosition)
272
throw new NoSuchElementException();
275
int start = currentPosition;
277
while ((currentPosition < maxPosition)
278
&& Character.isLetterOrDigit(str.charAt(currentPosition)))
283
if ((start == currentPosition)
284
&& (!Character.isLetterOrDigit(str.charAt(currentPosition))))
289
return str.substring(start, currentPosition);
293
* Tells if <code>nextToken</code> will throw an exception * if it is called.
295
* @return true if <code>nextToken</code> can be called * without throwing an exception.
297
boolean hasMoreTokens()
299
return (currentPosition >= maxPosition) ? false : true;
303
* Calculates the number of times that this tokenizer's
304
* <code>nextToken</code> method can be called before it generates an
307
* @return the number of tokens remaining in the string using the current
309
* @see java.util.StringTokenizer#nextToken()
315
int currpos = currentPosition;
317
while (currpos < maxPosition)
321
while ((currpos < maxPosition)
322
&& Character.isLetterOrDigit(str.charAt(currpos)))
327
if ((start == currpos)
328
&& (Character.isLetterOrDigit(str.charAt(currpos)) == false))
338
} // end NumberFormatStringTokenizer