KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > transformer > NumeratorFormatter


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */

16 /*
17  * $Id: NumeratorFormatter.java,v 1.8 2004/02/16 20:41:29 minchau Exp $
18  */

19 package org.apache.xalan.transformer;
20
21 import java.util.Locale JavaDoc;
22 import java.util.NoSuchElementException JavaDoc;
23
24 import org.w3c.dom.Element JavaDoc;
25
26 /**
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.
29  * @xsl.usage internal
30  */

31 class NumeratorFormatter
32 {
33
34   /** The owning xsl:number element. */
35   protected Element JavaDoc m_xslNumberElement;
36
37   /** An instance of a Tokenizer */
38   NumberFormatStringTokenizer m_formatTokenizer;
39
40   /** Locale we need to format in */
41   Locale JavaDoc m_locale;
42
43   /** An instance of a NumberFormat */
44   java.text.NumberFormat JavaDoc m_formatter;
45
46   /** An instance of a transformer */
47   TransformerImpl m_processor;
48
49   /**
50    * Table to help in converting decimals to roman numerals.
51    * @see org.apache.xalan.transformer.DecimalToRoman
52    */

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") };
61
62   /**
63    * Chars for converting integers into alpha counts.
64    * @see TransformerImpl#int2alphaCount
65    */

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' };
72
73   /**
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.
78    *
79    * @param xslNumberElement The given xsl:number element
80    * @param processor a non-null transformer instance
81    */

82   NumeratorFormatter(Element JavaDoc xslNumberElement, TransformerImpl processor)
83   {
84     m_xslNumberElement = xslNumberElement;
85     m_processor = processor;
86   } // end NumeratorFormatter(Element) constructor
87

88   /**
89    * Convert a long integer into alphabetic counting, in other words
90    * count using the sequence A B C ... Z AA AB AC.... etc.
91    *
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
96    *
97    * Note that the radix of the conversion is inferred from the size
98    * of the table.
99    */

100   protected String JavaDoc int2alphaCount(int val, char[] table)
101   {
102
103     int radix = table.length;
104
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];
109
110     // next character to set in the buffer
111
int charPos = buf.length - 1; // work backward through buf[]
112

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
115

116     // Correction number
117
//
118
// Correction can take on exactly two values:
119
//
120
// 0 if the next character is to be emitted is usual
121
//
122
// radix - 1
123
// if the next char to be emitted should be one less than
124
// you would expect
125
//
126
// For example, consider radix 10, where 1="A" and 10="J"
127
//
128
// In this scheme, we count: A, B, C ... H, I, J (not A0 and certainly
129
// not AJ), A1
130
//
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.
140
int correction = 0;
141
142     // TODO: throw error on out of range input
143
do
144     {
145
146       // most of the correction calculation is explained above, the reason for the
147
// term after the "|| " is that it correctly propagates carries across
148
// multiple columns.
149
correction =
150         ((lookupIndex == 0) || (correction != 0 && lookupIndex == radix - 1))
151         ? (radix - 1) : 0;
152
153       // index in "table" of the next char to emit
154
lookupIndex = (val + correction) % radix;
155
156       // shift input by one "column"
157
val = (val / radix);
158
159       // if the next value we'd put out would be a leading zero, we're done.
160
if (lookupIndex == 0 && val == 0)
161         break;
162
163       // put out the next character of output
164
buf[charPos--] = table[lookupIndex];
165     }
166     while (val > 0);
167
168     return new String JavaDoc(buf, charPos + 1, (buf.length - charPos - 1));
169   }
170
171   /**
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
179    */

180   String JavaDoc long2roman(long val, boolean prefixesAreOK)
181   {
182
183     if (val <= 0)
184     {
185       return "#E(" + val + ")";
186     }
187
188     String JavaDoc roman = "";
189     int place = 0;
190
191     if (val <= 3999L)
192     {
193       do
194       {
195         while (val >= m_romanConvertTable[place].m_postValue)
196         {
197           roman += m_romanConvertTable[place].m_postLetter;
198           val -= m_romanConvertTable[place].m_postValue;
199         }
200
201         if (prefixesAreOK)
202         {
203           if (val >= m_romanConvertTable[place].m_preValue)
204           {
205             roman += m_romanConvertTable[place].m_preLetter;
206             val -= m_romanConvertTable[place].m_preValue;
207           }
208         }
209
210         place++;
211       }
212       while (val > 0);
213     }
214     else
215     {
216       roman = "#error";
217     }
218
219     return roman;
220   } // end long2roman
221

222   /**
223    * This class returns tokens using non-alphanumberic
224    * characters as delimiters.
225    */

226   class NumberFormatStringTokenizer
227   {
228
229     /** Field holding the current position in the string */
230     private int currentPosition;
231
232     /** The total length of the string */
233     private int maxPosition;
234
235     /** The string to tokenize */
236     private String JavaDoc str;
237
238     /**
239      * Construct a NumberFormatStringTokenizer.
240      *
241      * @param str The string to tokenize
242      */

243     NumberFormatStringTokenizer(String JavaDoc str)
244     {
245       this.str = str;
246       maxPosition = str.length();
247     }
248     
249     /**
250      * Reset tokenizer so that nextToken() starts from the beginning.
251      *
252      */

253     void reset()
254     {
255       currentPosition = 0;
256     }
257
258     /**
259      * Returns the next token from this string tokenizer.
260      *
261      * @return the next token from this string tokenizer.
262      * @throws NoSuchElementException if there are no more tokens in this
263      * tokenizer's string.
264      */

265     String JavaDoc nextToken()
266     {
267
268       if (currentPosition >= maxPosition)
269       {
270         throw new NoSuchElementException JavaDoc();
271       }
272
273       int start = currentPosition;
274
275       while ((currentPosition < maxPosition)
276              && Character.isLetterOrDigit(str.charAt(currentPosition)))
277       {
278         currentPosition++;
279       }
280
281       if ((start == currentPosition)
282               && (!Character.isLetterOrDigit(str.charAt(currentPosition))))
283       {
284         currentPosition++;
285       }
286
287       return str.substring(start, currentPosition);
288     }
289
290     /**
291      * Tells if <code>nextToken</code> will throw an exception * if it is called.
292      *
293      * @return true if <code>nextToken</code> can be called * without throwing an exception.
294      */

295     boolean hasMoreTokens()
296     {
297       return (currentPosition >= maxPosition) ? false : true;
298     }
299
300     /**
301      * Calculates the number of times that this tokenizer's
302      * <code>nextToken</code> method can be called before it generates an
303      * exception.
304      *
305      * @return the number of tokens remaining in the string using the current
306      * delimiter set.
307      * @see java.util.StringTokenizer#nextToken()
308      */

309     int countTokens()
310     {
311
312       int count = 0;
313       int currpos = currentPosition;
314
315       while (currpos < maxPosition)
316       {
317         int start = currpos;
318
319         while ((currpos < maxPosition)
320                && Character.isLetterOrDigit(str.charAt(currpos)))
321         {
322           currpos++;
323         }
324
325         if ((start == currpos)
326                 && (Character.isLetterOrDigit(str.charAt(currpos)) == false))
327         {
328           currpos++;
329         }
330
331         count++;
332       }
333
334       return count;
335     }
336   } // end NumberFormatStringTokenizer
337
}
338
Popular Tags