~ubuntu-branches/ubuntu/precise/xom/precise

« back to all changes in this revision

Viewing changes to fatsrc/nu/xom/Text.java

  • Committer: Bazaar Package Importer
  • Author(s): Varun Hiremath
  • Date: 2007-11-25 15:50:40 UTC
  • Revision ID: james.westby@ubuntu.com-20071125155040-r75ikcqf1vu0cei7
Tags: upstream-1.1
ImportĀ upstreamĀ versionĀ 1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2002-2005 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
/**
 
25
 * <p>
 
26
 *   This class represents a run of text. 
 
27
 *   CDATA sections are not treated differently than 
 
28
 *   normal text. <code>Text</code> objects may be adjacent to other 
 
29
 *   <code>Text</code> objects.
 
30
 * </p>
 
31
 
 
32
 * @author Elliotte Rusty Harold
 
33
 * @version 1.1b4 fat
 
34
 *
 
35
 */
 
36
public class Text extends Node {
 
37
 
 
38
    
 
39
    private String data;
 
40
    
 
41
    
 
42
    /**
 
43
     * <p>
 
44
     * This constructor creates a new <code>Text</code> object. 
 
45
     * The data is checked for  legality according to XML 1.0 rules. 
 
46
     * Characters that can be serialized by escaping them 
 
47
     * such as &lt; and &amp; are allowed. However, characters  
 
48
     * such as the form feed, null, vertical tab,
 
49
     * unmatched halves of surrogate pairs,
 
50
     * and 0xFFFE and 0xFFFF are not allowed.
 
51
     * </p>
 
52
     * 
 
53
     * @param data the initial text of the object
 
54
     *
 
55
     * @throws IllegalCharacterDataException if data contains any 
 
56
     *     characters which are illegal in well-formed XML 1.0 such as 
 
57
     *     null, vertical tab, or unmatched halves of surrogate pairs
 
58
     */
 
59
    public Text(String data) {
 
60
        _setValue(data);
 
61
    }
 
62
 
 
63
    
 
64
    /**
 
65
     * <p>
 
66
     * Creates a copy of the specified <code>Text</code> object.
 
67
     * </p>
 
68
     * 
 
69
     * @param text the <code>Text</code> object to copy
 
70
     */
 
71
    public Text(Text text) {
 
72
        // I'm relying here on the data being immutable.
 
73
        // If this ever changes, e.g. by adding an append method,
 
74
        // this method needs to change too.
 
75
        this.data = text.data;
 
76
    }
 
77
 
 
78
    
 
79
    private Text() {}
 
80
    
 
81
    
 
82
    static Text build(String data) {
 
83
        Text result = new Text();
 
84
        result.data = data;
 
85
        return result;
 
86
    }
 
87
 
 
88
    
 
89
    /**
 
90
     * <p>
 
91
     * Sets the content of the <code>Text</code> object 
 
92
     * to the specified data. The data is checked for 
 
93
     * legality according to XML 1.0 rules. Characters that 
 
94
     * can be serialized such as &lt; and &amp; are allowed.   
 
95
     * However, characters such as the form feed, null, 
 
96
     * vertical tab, unmatched halves of surrogate pairs,
 
97
     * and 0xFFFE and 0xFFFF are not allowed.
 
98
     * </p>
 
99
     * 
 
100
     * @param data the text to install in the object
 
101
     * 
 
102
     * @throws IllegalCharacterDataException if data contains any 
 
103
     *     characters which are illegal in well-formed XML 1.0 such as 
 
104
     *     null, vertical tab, or unmatched halves of surrogate pairs
 
105
     */
 
106
    public void setValue(String data) {
 
107
        _setValue(data);
 
108
    }
 
109
 
 
110
    
 
111
    private void _setValue(String data) {
 
112
        
 
113
        if (data == null) this.data = "";
 
114
        else {
 
115
          // Interning all strings may be smaller than using UTF-8
 
116
          // but what does this do to performance? 
 
117
          // data = data.intern();
 
118
          Verifier.checkPCDATA(data);
 
119
          this.data = data;
 
120
        }
 
121
        
 
122
    }
 
123
 
 
124
    /**
 
125
     * <p>
 
126
     * Returns the XPath 1.0 string-value of this <code>Text</code> 
 
127
     * node. The XPath string-value of a text node is the same as 
 
128
     * the text of the node.
 
129
     * </p>
 
130
     *  
 
131
     * @return the content of the node
 
132
     */
 
133
    public final String getValue() {
 
134
        return this.data;
 
135
    }
 
136
 
 
137
    
 
138
    /**
 
139
     * <p>
 
140
     * Throws <code>IndexOutOfBoundsException</code> because 
 
141
     * texts do not have children.
 
142
     * </p>
 
143
     * 
 
144
     * @return never returns because texts do not have children;
 
145
     *     always throws an exception.
 
146
     * 
 
147
     * @param position the index of the child node to return
 
148
     * 
 
149
     * @throws IndexOutOfBoundsException because texts 
 
150
     *     do not have children
 
151
     */
 
152
    public final Node getChild(int position) {
 
153
        throw new IndexOutOfBoundsException(
 
154
          "LeafNodes do not have children");        
 
155
    }
 
156
 
 
157
    
 
158
    /**
 
159
     * <p>
 
160
     * Returns 0 because texts do not have children.
 
161
     * </p>
 
162
     * 
 
163
     * @return zero
 
164
     */
 
165
    public final int getChildCount() {
 
166
        return 0;   
 
167
    }
 
168
    
 
169
    
 
170
    /**
 
171
     * <p>
 
172
     * Returns a deep copy of this <code>Text</code> with no parent,
 
173
     * that can be added to this document or a different one.
 
174
     * </p>
 
175
     *
 
176
     * @return a deep copy of this text node with no parent
 
177
     */
 
178
    public Node copy() {
 
179
        
 
180
        if (isCDATASection()) {
 
181
            return new CDATASection(this);
 
182
        }
 
183
        else {
 
184
            return new Text(this);
 
185
        }
 
186
        
 
187
    }
 
188
 
 
189
    
 
190
    /**
 
191
     * <p>
 
192
     * Returns a string containing the XML serialization of this text 
 
193
     * node.  Unlike <code>getValue</code>, this method escapes 
 
194
     * characters such as &amp; and &lt; using entity references such
 
195
     * as <code>&amp;amp;</code> and <code>&amp;lt;</code>.
 
196
     * It escapes the carriage return (\r) as <code>&amp;#x0D;</code>.
 
197
     * </p>
 
198
     * 
 
199
     * @return the string form of this text node
 
200
     */
 
201
    public final String toXML() {
 
202
        return escapeText();    
 
203
    }
 
204
    
 
205
    
 
206
    boolean isText() {
 
207
        return true;   
 
208
    } 
 
209
 
 
210
 
 
211
    /**
 
212
     * <p>
 
213
     * Returns a <code>String</code> 
 
214
     * representation of this <code>Text</code> suitable for
 
215
     * debugging and diagnosis. This is <em>not</em>
 
216
     * the XML representation of this <code>Text</code> node.
 
217
     * </p>
 
218
     * 
 
219
     * @return a non-XML string representation of this node
 
220
     */
 
221
    public final String toString() {
 
222
        
 
223
        return "[" + getClass().getName() + ": " 
 
224
          + escapeLineBreaksAndTruncate(getValue()) + "]";
 
225
          
 
226
    }
 
227
    
 
228
    
 
229
    static String escapeLineBreaksAndTruncate(String s) {
 
230
        
 
231
        int length = s.length();
 
232
        boolean tooLong = length > 40;
 
233
        if (length > 40) {
 
234
            length = 35;
 
235
            s = s.substring(0, 35);
 
236
        }
 
237
        
 
238
        StringBuffer result = new StringBuffer(length);
 
239
        for (int i = 0; i < length; i++) {
 
240
            char c = s.charAt(i);
 
241
            switch (c) {
 
242
                case '\n': 
 
243
                    result.append("\\n");
 
244
                    break;
 
245
                case '\r': 
 
246
                    result.append("\\r");
 
247
                    break;
 
248
                case '\t': 
 
249
                    result.append("\\t");
 
250
                    break;
 
251
                default:
 
252
                    result.append(c);
 
253
            }
 
254
        }
 
255
        if (tooLong) result.append("...");
 
256
        
 
257
        return result.toString();
 
258
        
 
259
    }
 
260
 
 
261
    
 
262
    boolean isCDATASection() {
 
263
        return false;
 
264
    }
 
265
 
 
266
 
 
267
    boolean isEmpty() {
 
268
        return this.data.length() == 0;
 
269
    }
 
270
 
 
271
    String escapeText() {
 
272
        
 
273
        String s = getValue();
 
274
        int length = s.length();
 
275
        // Give the string buffer enough room for a couple of escaped characters 
 
276
        StringBuffer result = new StringBuffer(length+12);
 
277
        for (int i = 0; i < length; i++) {
 
278
            char c = s.charAt(i);
 
279
            switch (c) {
 
280
                case '\r':
 
281
                    result.append("&#x0D;");
 
282
                    break;
 
283
                case 14:
 
284
                    // impossible
 
285
                    break;
 
286
                case 15:
 
287
                    // impossible
 
288
                    break;
 
289
                case 16:
 
290
                    // impossible
 
291
                    break;
 
292
                case 17:
 
293
                    // impossible
 
294
                    break;
 
295
                case 18:
 
296
                    // impossible
 
297
                    break;
 
298
                case 19:
 
299
                    // impossible
 
300
                    break;
 
301
                case 20:
 
302
                    // impossible
 
303
                    break;
 
304
                case 21:
 
305
                    // impossible
 
306
                    break;
 
307
                case 22:
 
308
                    // impossible
 
309
                    break;
 
310
                case 23:
 
311
                    // impossible
 
312
                    break;
 
313
                case 24:
 
314
                    // impossible
 
315
                    break;
 
316
                case 25:
 
317
                    // impossible
 
318
                    break;
 
319
                case 26:
 
320
                    // impossible
 
321
                    break;
 
322
                case 27:
 
323
                    // impossible
 
324
                    break;
 
325
                case 28:
 
326
                    // impossible
 
327
                    break;
 
328
                case 29:
 
329
                    // impossible
 
330
                    break;
 
331
                case 30:
 
332
                    // impossible
 
333
                    break;
 
334
                case 31:
 
335
                    // impossible
 
336
                    break;
 
337
                case ' ':
 
338
                    result.append(' ');
 
339
                    break;
 
340
                case '!':
 
341
                    result.append('!');
 
342
                    break;
 
343
                case '"':
 
344
                    result.append('"');
 
345
                    break;
 
346
                case '#':
 
347
                    result.append('#');
 
348
                    break;
 
349
                case '$':
 
350
                    result.append('$');
 
351
                    break;
 
352
                case '%':
 
353
                    result.append('%');
 
354
                    break;
 
355
                case '&':
 
356
                    result.append("&amp;");
 
357
                    break;
 
358
                case '\'':
 
359
                    result.append('\'');
 
360
                    break;
 
361
                case '(':
 
362
                    result.append('(');
 
363
                    break;
 
364
                case ')':
 
365
                    result.append(')');
 
366
                    break;
 
367
                case '*':
 
368
                    result.append('*');
 
369
                    break;
 
370
                case '+':
 
371
                    result.append('+');
 
372
                    break;
 
373
                case ',':
 
374
                    result.append(',');
 
375
                    break;
 
376
                case '-':
 
377
                    result.append('-');
 
378
                    break;
 
379
                case '.':
 
380
                    result.append('.');
 
381
                    break;
 
382
                case '/':
 
383
                    result.append('/');
 
384
                    break;
 
385
                case '0':
 
386
                    result.append('0');
 
387
                    break;
 
388
                case '1':
 
389
                    result.append('1');
 
390
                    break;
 
391
                case '2':
 
392
                    result.append('2');
 
393
                    break;
 
394
                case '3':
 
395
                    result.append('3');
 
396
                    break;
 
397
                case '4':
 
398
                    result.append('4');
 
399
                    break;
 
400
                case '5':
 
401
                    result.append('5');
 
402
                    break;
 
403
                case '6':
 
404
                    result.append('6');
 
405
                    break;
 
406
                case '7':
 
407
                    result.append('7');
 
408
                    break;
 
409
                case '8':
 
410
                    result.append('8');
 
411
                    break;
 
412
                case '9':
 
413
                    result.append('9');
 
414
                    break;
 
415
                case ':':
 
416
                    result.append(':');
 
417
                    break;
 
418
                case ';':
 
419
                    result.append(';');
 
420
                    break;
 
421
                case '<':
 
422
                    result.append("&lt;");
 
423
                    break;
 
424
                case '=':
 
425
                    result.append('=');
 
426
                    break;
 
427
                case '>':
 
428
                    result.append("&gt;");
 
429
                    break;
 
430
                default: 
 
431
                    result.append(c); 
 
432
            }  
 
433
        }
 
434
        
 
435
        return result.toString();
 
436
        
 
437
    }
 
438
        
 
439
}
 
 
b'\\ No newline at end of file'