KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > nu > xom > Text


1 /* Copyright 2002-2004 Elliotte Rusty Harold
2    
3    This library is free software; you can redistribute it and/or modify
4    it under the terms of version 2.1 of the GNU Lesser General Public
5    License as published by the Free Software Foundation.
6    
7    This library is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10    GNU Lesser General Public License for more details.
11    
12    You should have received a copy of the GNU Lesser General Public
13    License along with this library; if not, write to the
14    Free Software Foundation, Inc., 59 Temple Place, Suite 330,
15    Boston, MA 02111-1307 USA
16    
17    You can contact Elliotte Rusty Harold by sending e-mail to
18    elharo@metalab.unc.edu. Please include the word "XOM" in the
19    subject line. The XOM home page is located at http://www.xom.nu/
20 */

21
22 package nu.xom;
23
24 import java.io.UnsupportedEncodingException JavaDoc;
25
26 /**
27  * <p>
28  * This class represents a run of text.
29  * CDATA sections are not treated differently than
30  * normal text.
31  * </p>
32
33  * @author Elliotte Rusty Harold
34  * @version 1.0
35  *
36  */

37 public class Text extends Node {
38
39     
40     private byte[] data;
41     
42     
43     /**
44      * <p>
45      * This constructor creates a new <code>Text</code> object.
46      * The data is checked for legality according to XML 1.0 rules.
47      * Characters that can be serialized by escaping them
48      * such as &lt; and &amp; are allowed. However, characters
49      * such as the form feed, null, vertical tab,
50      * unmatched halves of surrogate pairs,
51      * and 0xFFFE and 0xFFFF are not allowed.
52      * </p>
53      *
54      * @param data the initial text of the object
55      *
56      * @throws IllegalCharacterDataException if data contains any
57      * characters which are illegal in well-formed XML 1.0 such as
58      * null, vertical tab, or unmatched halves of surrogate pairs
59      */

60     public Text(String JavaDoc data) {
61         _setValue(data);
62     }
63
64     
65     /**
66      * <p>
67      * Creates a copy of the specified <code>Text</code> object.
68      * </p>
69      *
70      * @param text the <code>Text</code> object to copy
71      */

72     public Text(Text text) {
73         // I'm relying here on the data array being immutable.
74
// If this ever changes, e.g. by adding an append method,
75
// this method needs to change too.
76
this.data = text.data;
77     }
78
79     
80     private Text() {}
81     
82     
83     static Text build(String JavaDoc data) {
84         
85         Text result = new Text();
86         try {
87             result.data = data.getBytes("UTF8");
88         }
89         catch (UnsupportedEncodingException JavaDoc ex) {
90             throw new RuntimeException JavaDoc(
91               "Bad VM! Does not support UTF-8"
92             );
93         }
94         return result;
95         
96     }
97
98     
99     /**
100      * <p>
101      * Sets the content of the <code>Text</code> object
102      * to the specified data. The data is checked for
103      * legality according to XML 1.0 rules. Characters that
104      * can be serialized such as &lt; and &amp; are allowed.
105      * However, characters such as the form feed, null,
106      * vertical tab, unmatched halves of surrogate pairs,
107      * and 0xFFFE and 0xFFFF are not allowed.
108      * </p>
109      *
110      * @param data the text to install in the object
111      *
112      * @throws IllegalCharacterDataException if data contains any
113      * characters which are illegal in well-formed XML 1.0 such as
114      * null, vertical tab, or unmatched halves of surrogate pairs
115      */

116     public void setValue(String JavaDoc data) {
117         _setValue(data);
118     }
119
120     
121     private void _setValue(String JavaDoc data) {
122         
123         if (data == null) data = "";
124         else Verifier.checkPCDATA(data);
125         try {
126             this.data = data.getBytes("UTF8");
127         }
128         catch (UnsupportedEncodingException JavaDoc ex) {
129             throw new RuntimeException JavaDoc(
130               "Bad VM! Does not support UTF-8"
131             );
132         }
133         
134     }
135
136     /**
137      * <p>
138      * Returns the XPath 1.0 string-value of this <code>Text</code>
139      * node. The XPath string-value of a text node is the same as
140      * the text of the node.
141      * </p>
142      *
143      * @return The content of the node.
144      */

145     public final String JavaDoc getValue() {
146         
147         try {
148             return new String JavaDoc(data, "UTF8");
149         }
150         catch (UnsupportedEncodingException JavaDoc ex) {
151             throw new RuntimeException JavaDoc(
152               "Bad VM! Does not support UTF-8"
153             );
154         }
155         
156     }
157
158     
159     /**
160      * <p>
161      * Throws <code>IndexOutOfBoundsException</code> because
162      * texts do not have children.
163      * </p>
164      *
165      * @return never returns because texts do not have children;
166      * always throws an exception.
167      *
168      * @param position the index of the child node to return
169      *
170      * @throws IndexOutOfBoundsException because texts
171      * do not have children
172      */

173     public final Node getChild(int position) {
174         throw new IndexOutOfBoundsException JavaDoc(
175           "LeafNodes do not have children");
176     }
177
178     
179     /**
180      * <p>
181      * Returns 0 because texts do not have children.
182      * </p>
183      *
184      * @return zero
185      */

186     public final int getChildCount() {
187         return 0;
188     }
189     
190     
191     /**
192      * <p>
193      * Returns a deep copy of this <code>Text</code> with no parent,
194      * that can be added to this document or a different one.
195      * </p>
196      *
197      * @return a deep copy of this text node with no parent
198      */

199     public Node copy() {
200         
201         if (isCDATASection()) {
202             return new CDATASection(this);
203         }
204         else {
205             return new Text(this);
206         }
207         
208     }
209
210     
211     /**
212      * <p>
213      * Returns a string containing the XML serialization of this text
214      * node. Unlike <code>getValue</code>, this method escapes
215      * characters such as &amp; and &lt; using entity references such
216      * as <code>&amp;amp;</code> and <code>&amp;lt;</code>.
217      * It escapes the carriage return (\r) as <code>&amp;#x0D;</code>.
218      * </p>
219      *
220      * @return the string form of this text node
221      */

222     public final String JavaDoc toXML() {
223         return escapeText(getValue());
224     }
225
226     
227     private static String JavaDoc escapeText(String JavaDoc s) {
228         
229         int length = s.length();
230         // Give the string buffer enough room for a couple of escaped characters
231
StringBuffer JavaDoc result = new StringBuffer JavaDoc(length+12);
232         for (int i = 0; i < length; i++) {
233             char c = s.charAt(i);
234             switch (c) {
235                 case '\r':
236                     result.append("&#x0D;");
237                     break;
238                 case 14:
239                     // impossible
240
break;
241                 case 15:
242                     // impossible
243
break;
244                 case 16:
245                     // impossible
246
break;
247                 case 17:
248                     // impossible
249
break;
250                 case 18:
251                     // impossible
252
break;
253                 case 19:
254                     // impossible
255
break;
256                 case 20:
257                     // impossible
258
break;
259                 case 21:
260                     // impossible
261
break;
262                 case 22:
263                     // impossible
264
break;
265                 case 23:
266                     // impossible
267
break;
268                 case 24:
269                     // impossible
270
break;
271                 case 25:
272                     // impossible
273
break;
274                 case 26:
275                     // impossible
276
break;
277                 case 27:
278                     // impossible
279
break;
280                 case 28:
281                     // impossible
282
break;
283                 case 29:
284                     // impossible
285
break;
286                 case 30:
287                     // impossible
288
break;
289                 case 31:
290                     // impossible
291
break;
292                 case ' ':
293                     result.append(' ');
294                     break;
295                 case '!':
296                     result.append('!');
297                     break;
298                 case '"':
299                     result.append('"');
300                     break;
301                 case '#':
302                     result.append('#');
303                     break;
304                 case '$':
305                     result.append('$');
306                     break;
307                 case '%':
308                     result.append('%');
309                     break;
310                 case '&':
311                     result.append("&amp;");
312                     break;
313                 case '\'':
314                     result.append('\'');
315                     break;
316                 case '(':
317                     result.append('(');
318                     break;
319                 case ')':
320                     result.append(')');
321                     break;
322                 case '*':
323                     result.append('*');
324                     break;
325                 case '+':
326                     result.append('+');
327                     break;
328                 case ',':
329                     result.append(',');
330                     break;
331                 case '-':
332                     result.append('-');
333                     break;
334                 case '.':
335                     result.append('.');
336                     break;
337                 case '/':
338                     result.append('/');
339                     break;
340                 case '0':
341                     result.append('0');
342                     break;
343                 case '1':
344                     result.append('1');
345                     break;
346                 case '2':
347                     result.append('2');
348                     break;
349                 case '3':
350                     result.append('3');
351                     break;
352                 case '4':
353                     result.append('4');
354                     break;
355                 case '5':
356                     result.append('5');
357                     break;
358                 case '6':
359                     result.append('6');
360                     break;
361                 case '7':
362                     result.append('7');
363                     break;
364                 case '8':
365                     result.append('8');
366                     break;
367                 case '9':
368                     result.append('9');
369                     break;
370                 case ':':
371                     result.append(':');
372                     break;
373                 case ';':
374                     result.append(';');
375                     break;
376                 case '<':
377                     result.append("&lt;");
378                     break;
379                 case '=':
380                     result.append('=');
381                     break;
382                 case '>':
383                     result.append("&gt;");
384                     break;
385                 default:
386                     result.append(c);
387             }
388         }
389         
390         return result.toString();
391         
392     }
393     
394     
395     boolean isText() {
396         return true;
397     }
398
399
400     /**
401      * <p>
402      * Returns a <code>String</code>
403      * representation of this <code>Text</code> suitable for
404      * debugging and diagnosis. This is <em>not</em>
405      * the XML representation of this <code>Text</code> node.
406      * </p>
407      *
408      * @return a non-XML string representation of this node
409      */

410     public final String JavaDoc toString() {
411         
412         return "[" + getClass().getName() + ": "
413           + escapeLineBreaksAndTruncate(getValue()) + "]";
414           
415     }
416     
417     
418     static String JavaDoc escapeLineBreaksAndTruncate(String JavaDoc s) {
419         
420         int length = s.length();
421         boolean tooLong = length > 40;
422         if (length > 40) {
423             length = 35;
424             s = s.substring(0, 35);
425         }
426         
427         StringBuffer JavaDoc result = new StringBuffer JavaDoc(length);
428         for (int i = 0; i < length; i++) {
429             char c = s.charAt(i);
430             switch (c) {
431                 case '\n':
432                     result.append("\\n");
433                     break;
434                 case '\r':
435                     result.append("\\r");
436                     break;
437                 case '\t':
438                     result.append("\\t");
439                     break;
440                 default:
441                     result.append(c);
442             }
443         }
444         if (tooLong) result.append("...");
445         
446         return result.toString();
447         
448     }
449
450     
451     boolean isCDATASection() {
452         return false;
453     }
454
455
456     boolean isEmpty() {
457         return this.data.length == 0;
458     }
459
460     
461 }
Popular Tags