KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > xsltc > dom > NodeCounter


1 /*
2  * Copyright 2001-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: NodeCounter.java,v 1.10 2004/02/16 22:54:59 minchau Exp $
18  */

19
20 package org.apache.xalan.xsltc.dom;
21
22 import java.util.Vector JavaDoc;
23
24 import org.apache.xalan.xsltc.DOM;
25 import org.apache.xalan.xsltc.Translet;
26 import org.apache.xml.dtm.DTM;
27 import org.apache.xml.dtm.DTMAxisIterator;
28
29 /**
30  * @author Jacek Ambroziak
31  * @author Santiago Pericas-Geertsen
32  * @author Morten Jorgensen
33  */

34 public abstract class NodeCounter implements Axis {
35     public static final int END = DTM.NULL;
36
37     protected int _node = END;
38     protected int _nodeType = DOM.FIRST_TYPE - 1;
39     protected int _value = Integer.MIN_VALUE;
40
41     public final DOM _document;
42     public final DTMAxisIterator _iterator;
43     public final Translet _translet;
44
45     protected String JavaDoc _format;
46     protected String JavaDoc _lang;
47     protected String JavaDoc _letterValue;
48     protected String JavaDoc _groupSep;
49     protected int _groupSize;
50
51     private boolean separFirst = true;
52     private boolean separLast = false;
53     private Vector JavaDoc separToks = null;
54     private Vector JavaDoc formatToks = null;
55     private int nSepars = 0;
56     private int nFormats = 0;
57
58     private static String JavaDoc[] Thousands =
59         {"", "m", "mm", "mmm" };
60     private static String JavaDoc[] Hundreds =
61     {"", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm"};
62     private static String JavaDoc[] Tens =
63     {"", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"};
64     private static String JavaDoc[] Ones =
65     {"", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"};
66
67     protected NodeCounter(Translet translet,
68               DOM document, DTMAxisIterator iterator) {
69     _translet = translet;
70     _document = document;
71     _iterator = iterator;
72     }
73
74     /**
75      * Set the start node for this counter. The same <tt>NodeCounter</tt>
76      * object can be used multiple times by resetting the starting node.
77      */

78     abstract public NodeCounter setStartNode(int node);
79
80     /**
81      * If the user specified a value attribute, use this instead of
82      * counting nodes.
83      */

84     public NodeCounter setValue(int value) {
85     _value = value;
86     return this;
87     }
88
89     /**
90      * Sets formatting fields before calling formatNumbers().
91      */

92     protected void setFormatting(String JavaDoc format, String JavaDoc lang, String JavaDoc letterValue,
93                  String JavaDoc groupSep, String JavaDoc groupSize) {
94     _lang = lang;
95     _format = format;
96     _groupSep = groupSep;
97     _letterValue = letterValue;
98
99     try {
100         _groupSize = Integer.parseInt(groupSize);
101     }
102     catch (NumberFormatException JavaDoc e) {
103         _groupSize = 0;
104     }
105
106     final int length = _format.length();
107     boolean isFirst = true;
108     separFirst = true;
109     separLast = false;
110
111         separToks = new Vector JavaDoc();
112         formatToks = new Vector JavaDoc();
113
114     /*
115      * Tokenize the format string into alphanumeric and non-alphanumeric
116      * tokens as described in M. Kay page 241.
117      */

118     for (int j = 0, i = 0; i < length;) {
119             char c = _format.charAt(i);
120             for (j = i; Character.isLetterOrDigit(c);) {
121                 if (++i == length) break;
122         c = _format.charAt(i);
123             }
124             if (i > j) {
125                 if (isFirst) {
126                     separToks.addElement(".");
127                     isFirst = separFirst = false;
128                 }
129                 formatToks.addElement(_format.substring(j, i));
130             }
131
132             if (i == length) break;
133
134             c = _format.charAt(i);
135             for (j = i; !Character.isLetterOrDigit(c);) {
136                 if (++i == length) break;
137                 c = _format.charAt(i);
138                 isFirst = false;
139             }
140             if (i > j) {
141                 separToks.addElement(_format.substring(j, i));
142             }
143         }
144
145     nSepars = separToks.size();
146     nFormats = formatToks.size();
147     if (nSepars > nFormats) separLast = true;
148
149     if (separFirst) nSepars--;
150     if (separLast) nSepars--;
151     if (nSepars == 0) {
152         separToks.insertElementAt(".", 1);
153         nSepars++;
154     }
155     if (separFirst) nSepars ++;
156     }
157
158     /**
159      * Sets formatting fields to their default values.
160      */

161     public NodeCounter setDefaultFormatting() {
162     setFormatting("1", "en", "alphabetic", null, null);
163     return this;
164     }
165
166     /**
167      * Returns the position of <tt>node</tt> according to the level and
168      * the from and count patterns.
169      */

170     abstract public String JavaDoc getCounter();
171
172     /**
173      * Returns the position of <tt>node</tt> according to the level and
174      * the from and count patterns. This position is converted into a
175      * string based on the arguments passed.
176      */

177     public String JavaDoc getCounter(String JavaDoc format, String JavaDoc lang, String JavaDoc letterValue,
178                  String JavaDoc groupSep, String JavaDoc groupSize) {
179     setFormatting(format, lang, letterValue, groupSep, groupSize);
180     return getCounter();
181     }
182
183     /**
184      * Returns true if <tt>node</tt> matches the count pattern. By
185      * default a node matches the count patterns if it is of the
186      * same type as the starting node.
187      */

188     public boolean matchesCount(int node) {
189     return _nodeType == _document.getExpandedTypeID(node);
190     }
191
192     /**
193      * Returns true if <tt>node</tt> matches the from pattern. By default,
194      * no node matches the from pattern.
195      */

196     public boolean matchesFrom(int node) {
197     return false;
198     }
199
200     /**
201      * Format a single value according to the format parameters.
202      */

203     protected String JavaDoc formatNumbers(int value) {
204     return formatNumbers(new int[] { value });
205     }
206
207     /**
208      * Format a sequence of values according to the format paramaters
209      * set by calling setFormatting().
210      */

211     protected String JavaDoc formatNumbers(int[] values) {
212     final int nValues = values.length;
213     final int length = _format.length();
214
215     boolean isEmpty = true;
216     for (int i = 0; i < nValues; i++)
217         if (values[i] != Integer.MIN_VALUE)
218         isEmpty = false;
219     if (isEmpty) return("");
220
221     // Format the output string using the values array and the fmt. tokens
222
boolean isFirst = true;
223     int t = 0, n = 0, s = 1;
224     final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
225
226     // Append separation token before first digit/letter/numeral
227
if (separFirst) buffer.append((String JavaDoc)separToks.elementAt(0));
228
229     // Append next digit/letter/numeral and separation token
230
while (n < nValues) {
231         final int value = values[n];
232         if (value != Integer.MIN_VALUE) {
233         if (!isFirst) buffer.append((String JavaDoc) separToks.elementAt(s++));
234         formatValue(value, (String JavaDoc)formatToks.elementAt(t++), buffer);
235         if (t == nFormats) t--;
236         if (s >= nSepars) s--;
237         isFirst = false;
238         }
239         n++;
240     }
241
242     // Append separation token after last digit/letter/numeral
243
if (separLast) buffer.append((String JavaDoc)separToks.lastElement());
244     return buffer.toString();
245     }
246
247     /**
248      * Format a single value based on the appropriate formatting token.
249      * This method is based on saxon (Michael Kay) and only implements
250      * lang="en".
251      */

252     private void formatValue(int value, String JavaDoc format, StringBuffer JavaDoc buffer) {
253         char c = format.charAt(0);
254
255         if (Character.isDigit(c)) {
256             char zero = (char)(c - Character.getNumericValue(c));
257
258             StringBuffer JavaDoc temp = buffer;
259             if (_groupSize > 0) {
260                 temp = new StringBuffer JavaDoc();
261             }
262             String JavaDoc s = "";
263             int n = value;
264             while (n > 0) {
265                 s = (char) ((int) zero + (n % 10)) + s;
266                 n = n / 10;
267             }
268                 
269             for (int i = 0; i < format.length() - s.length(); i++) {
270                 temp.append(zero);
271             }
272             temp.append(s);
273             
274             if (_groupSize > 0) {
275                 for (int i = 0; i < temp.length(); i++) {
276                     if (i != 0 && ((temp.length() - i) % _groupSize) == 0) {
277                         buffer.append(_groupSep);
278                     }
279                     buffer.append(temp.charAt(i));
280                 }
281             }
282         }
283     else if (c == 'i' && !_letterValue.equals("alphabetic")) {
284             buffer.append(romanValue(value));
285         }
286     else if (c == 'I' && !_letterValue.equals("alphabetic")) {
287             buffer.append(romanValue(value).toUpperCase());
288         }
289     else {
290         int min = (int) c;
291         int max = (int) c;
292
293         // Special case for Greek alphabet
294
if (c >= 0x3b1 && c <= 0x3c9) {
295         max = 0x3c9; // omega
296
}
297         else {
298         // General case: search for end of group
299
while (Character.isLetterOrDigit((char) (max + 1))) {
300             max++;
301         }
302         }
303             buffer.append(alphaValue(value, min, max));
304         }
305     }
306
307     private String JavaDoc alphaValue(int value, int min, int max) {
308         if (value <= 0) {
309         return "" + value;
310     }
311
312         int range = max - min + 1;
313         char last = (char)(((value-1) % range) + min);
314         if (value > range) {
315             return alphaValue((value-1) / range, min, max) + last;
316         }
317     else {
318             return "" + last;
319         }
320     }
321
322     private String JavaDoc romanValue(int n) {
323         if (n <= 0 || n > 4000) {
324         return "" + n;
325     }
326         return
327         Thousands[n / 1000] +
328         Hundreds[(n / 100) % 10] +
329         Tens[(n/10) % 10] +
330         Ones[n % 10];
331     }
332 }
333
334
Popular Tags