KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > prefuse > util > io > XMLWriter


1 /**
2  * Copyright (c) 2004-2006 Regents of the University of California.
3  * See "license-prefuse.txt" for licensing terms.
4  */

5 package prefuse.util.io;
6
7 import java.io.PrintWriter JavaDoc;
8 import java.util.ArrayList JavaDoc;
9
10 /**
11  * Utility class for writing XML files. This class provides convenience
12  * methods for creating XML documents, such as starting and ending
13  * tags, and adding content and comments. This class handles correct
14  * XML formatting and will properly escape text to ensure that the
15  * text remains valid XML.
16  *
17  * <p>To use this class, create a new instance with the desired
18  * PrintWriter to write the XML to. Call the {@link #begin()} or
19  * {@link #begin(String, int)} method when ready to start outputting
20  * XML. Then use the provided methods to generate the XML file.
21  * Finally, call either the {@link #finish()} or {@link #finish(String)}
22  * methods to signal the completion of the file.</p>
23  *
24  * @author <a HREF="http://jheer.org">jeffrey heer</a>
25  */

26 public class XMLWriter {
27     
28     private PrintWriter JavaDoc m_out;
29     private int m_bias = 0;
30     private int m_tab;
31     private ArrayList JavaDoc m_tagStack = new ArrayList JavaDoc();
32     
33     /**
34      * Create a new XMLWriter.
35      * @param out the print writer to write the XML to
36      */

37     public XMLWriter(PrintWriter JavaDoc out) {
38         this(out, 2);
39     }
40
41     /**
42      * Create a new XMLWriter.
43      * @param out the print writer to write the XML to
44      * @param tabLength the number of spaces to use for each
45      * level of indentation in the XML file
46      */

47     public XMLWriter(PrintWriter JavaDoc out, int tabLength) {
48         m_out = out;
49         m_tab = 2;
50     }
51     
52     /**
53      * Print <em>unescaped</em> text into the XML file. To print
54      * escaped text, use the {@link #content(String)} method instead.
55      * @param s the text to print. This String will not be escaped.
56      */

57     public void print(String JavaDoc s) {
58         m_out.print(s);
59     }
60
61     /**
62      * Print <em>unescaped</em> text into the XML file, followed by
63      * a newline. To print escaped text, use the {@link #content(String)}
64      * method instead.
65      * @param s the text to print. This String will not be escaped.
66      */

67     public void println(String JavaDoc s) {
68         m_out.print(s);
69         m_out.print("\n");
70     }
71     
72     /**
73      * Print a newline into the XML file.
74      */

75     public void println() {
76         m_out.print("\n");
77     }
78     
79     /**
80      * Begin the XML document. This must be called before any other
81      * formatting methods. This method prints an XML header into
82      * the top of the output stream.
83      */

84     public void begin() {
85         m_out.print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
86         println();
87     }
88     
89     /**
90      * Begin the XML document. This must be called before any other
91      * formatting methods. This method prints an XML header into
92      * the top of the output stream, plus additional header text
93      * provided by the client
94      * @param header header text to insert into the document
95      * @param bias the spacing bias to use for all subsequent indenting
96      */

97     public void begin(String JavaDoc header, int bias) {
98         begin();
99         m_out.print(header);
100         m_bias = bias;
101     }
102     
103     /**
104      * Print a comment in the XML document. The comment will be printed
105      * according to the current spacing and followed by a newline.
106      * @param comment the comment text
107      */

108     public void comment(String JavaDoc comment) {
109         spacing();
110         m_out.print("<!-- ");
111         m_out.print(comment);
112         m_out.print(" -->");
113         println();
114     }
115     
116     /**
117      * Internal method for printing a tag with attributes.
118      * @param tag the tag name
119      * @param names the names of the attributes
120      * @param values the values of the attributes
121      * @param nattr the number of attributes
122      * @param close true to close the tag, false to leave it
123      * open and adjust the spacing
124      */

125     protected void tag(String JavaDoc tag, String JavaDoc[] names, String JavaDoc[] values,
126             int nattr, boolean close)
127     {
128         spacing();
129         m_out.print('<');
130         m_out.print(tag);
131         for ( int i=0; i<nattr; ++i ) {
132             m_out.print(' ');
133             m_out.print(names[i]);
134             m_out.print('=');
135             m_out.print('\"');
136             escapeString(values[i]);
137             m_out.print('\"');
138         }
139         if ( close ) m_out.print('/');
140         m_out.print('>');
141         println();
142         
143         if ( !close ) {
144             m_tagStack.add(tag);
145         }
146     }
147     
148     /**
149      * Print a closed tag with attributes. The tag will be followed by a
150      * newline.
151      * @param tag the tag name
152      * @param names the names of the attributes
153      * @param values the values of the attributes
154      * @param nattr the number of attributes
155      */

156     public void tag(String JavaDoc tag, String JavaDoc[] names, String JavaDoc[] values, int nattr)
157     {
158         tag(tag, names, values, nattr, true);
159     }
160     
161     /**
162      * Print a start tag with attributes. The tag will be followed by a
163      * newline, and the indentation level will be increased.
164      * @param tag the tag name
165      * @param names the names of the attributes
166      * @param values the values of the attributes
167      * @param nattr the number of attributes
168      */

169     public void start(String JavaDoc tag, String JavaDoc[] names, String JavaDoc[] values, int nattr)
170     {
171         tag(tag, names, values, nattr, false);
172     }
173     
174     /**
175      * Internal method for printing a tag with a single attribute.
176      * @param tag the tag name
177      * @param name the name of the attribute
178      * @param value the value of the attribute
179      * @param close true to close the tag, false to leave it
180      * open and adjust the spacing
181      */

182     protected void tag(String JavaDoc tag, String JavaDoc name, String JavaDoc value, boolean close) {
183         spacing();
184         m_out.print('<');
185         m_out.print(tag);
186         m_out.print(' ');
187         m_out.print(name);
188         m_out.print('=');
189         m_out.print('\"');
190         escapeString(value);
191         m_out.print('\"');
192         if ( close ) m_out.print('/');
193         m_out.print('>');
194         println();
195         
196         if ( !close ) {
197             m_tagStack.add(tag);
198         }
199     }
200     
201     /**
202      * Print a closed tag with one attribute. The tag will be followed by a
203      * newline.
204      * @param tag the tag name
205      * @param name the name of the attribute
206      * @param value the value of the attribute
207      */

208     public void tag(String JavaDoc tag, String JavaDoc name, String JavaDoc value)
209     {
210         tag(tag, name, value, true);
211     }
212     
213     /**
214      * Print a start tag with one attribute. The tag will be followed by a
215      * newline, and the indentation level will be increased.
216      * @param tag the tag name
217      * @param name the name of the attribute
218      * @param value the value of the attribute
219      */

220     public void start(String JavaDoc tag, String JavaDoc name, String JavaDoc value)
221     {
222         tag(tag, name, value, false);
223     }
224     
225     /**
226      * Internal method for printing a tag with attributes.
227      * @param tag the tag name
228      * @param names the names of the attributes
229      * @param values the values of the attributes
230      * @param nattr the number of attributes
231      * @param close true to close the tag, false to leave it
232      * open and adjust the spacing
233      */

234     protected void tag(String JavaDoc tag, ArrayList JavaDoc names, ArrayList JavaDoc values,
235             int nattr, boolean close)
236     {
237         spacing();
238         m_out.print('<');
239         m_out.print(tag);
240         for ( int i=0; i<nattr; ++i ) {
241             m_out.print(' ');
242             m_out.print((String JavaDoc)names.get(i));
243             m_out.print('=');
244             m_out.print('\"');
245             escapeString((String JavaDoc)values.get(i));
246             m_out.print('\"');
247         }
248         if ( close ) m_out.print('/');
249         m_out.print('>');
250         println();
251         
252         if ( !close ) {
253             m_tagStack.add(tag);
254         }
255     }
256     
257     /**
258      * Print a closed tag with attributes. The tag will be followed by a
259      * newline.
260      * @param tag the tag name
261      * @param names the names of the attributes
262      * @param values the values of the attributes
263      * @param nattr the number of attributes
264      */

265     public void tag(String JavaDoc tag, ArrayList JavaDoc names, ArrayList JavaDoc values, int nattr)
266     {
267         tag(tag, names, values, nattr, true);
268     }
269     
270     /**
271      * Print a start tag with attributes. The tag will be followed by a
272      * newline, and the indentation level will be increased.
273      * @param tag the tag name
274      * @param names the names of the attributes
275      * @param values the values of the attributes
276      * @param nattr the number of attributes
277      */

278     public void start(String JavaDoc tag, ArrayList JavaDoc names, ArrayList JavaDoc values, int nattr)
279     {
280         tag(tag, names, values, nattr, false);
281     }
282     
283     /**
284      * Print a start tag without attributes. The tag will be followed by a
285      * newline, and the indentation level will be increased.
286      * @param tag the tag name
287      */

288     public void start(String JavaDoc tag) {
289         tag(tag, (String JavaDoc[])null, null, 0, false);
290     }
291
292     /**
293      * Close the most recently opened tag. The tag will be followed by a
294      * newline, and the indentation level will be decreased.
295      */

296     public void end() {
297         String JavaDoc tag = (String JavaDoc)m_tagStack.remove(m_tagStack.size()-1);
298         spacing();
299         m_out.print('<');
300         m_out.print('/');
301         m_out.print(tag);
302         m_out.print('>');
303         println();
304     }
305     
306     /**
307      * Print a new content tag with a single attribute, consisting of an
308      * open tag, content text, and a closing tag, all on one line.
309      * @param tag the tag name
310      * @param name the name of the attribute
311      * @param value the value of the attribute, this text will be escaped
312      * @param content the text content, this text will be escaped
313      */

314     public void contentTag(String JavaDoc tag, String JavaDoc name, String JavaDoc value,
315                            String JavaDoc content)
316     {
317         spacing();
318         m_out.print('<'); m_out.print(tag); m_out.print(' ');
319         m_out.print(name); m_out.print('=');
320         m_out.print('\"'); escapeString(value); m_out.print('\"');
321         m_out.print('>');
322         escapeString(content);
323         m_out.print('<'); m_out.print('/'); m_out.print(tag); m_out.print('>');
324         println();
325     }
326     
327     /**
328      * Print a new content tag with no attributes, consisting of an
329      * open tag, content text, and a closing tag, all on one line.
330      * @param tag the tag name
331      * @param content the text content, this text will be escaped
332      */

333     public void contentTag(String JavaDoc tag, String JavaDoc content) {
334         spacing();
335         m_out.print('<'); m_out.print(tag); m_out.print('>');
336         escapeString(content);
337         m_out.print('<'); m_out.print('/'); m_out.print(tag); m_out.print('>');
338         println();
339     }
340     
341     /**
342      * Print content text.
343      * @param content the content text, this text will be escaped
344      */

345     public void content(String JavaDoc content) {
346         escapeString(content);
347     }
348     
349     /**
350      * Finish the XML document.
351      */

352     public void finish() {
353         m_bias = 0;
354         m_out.flush();
355     }
356     
357     /**
358      * Finish the XML document, printing the given footer text at the
359      * end of the document.
360      * @param footer the footer text, this will not be escaped
361      */

362     public void finish(String JavaDoc footer) {
363         m_bias = 0;
364         m_out.print(footer);
365         m_out.flush();
366     }
367     
368     /**
369      * Print the current spacing (determined by the indentation level)
370      * into the document. This method is used by many of the other
371      * formatting methods, and so should only need to be called in
372      * the case of custom text printing outside the mechanisms
373      * provided by this class.
374      */

375     public void spacing() {
376         int len = m_bias + m_tagStack.size() * m_tab;
377         for ( int i=0; i<len; ++i )
378             m_out.print(' ');
379     }
380     
381     // ------------------------------------------------------------------------
382
// Escape Text
383

384     // unicode ranges and valid/invalid characters
385
private static final char LOWER_RANGE = 0x20;
386     private static final char UPPER_RANGE = 0x7f;
387     private static final char[] VALID_CHARS = { 0x9, 0xA, 0xD };
388     
389     private static final char[] INVALID = { '<', '>', '"', '\'', '&' };
390     private static final String JavaDoc[] VALID =
391         { "&lt;", "&gt;", "&quot;", "&apos;", "&amp;" };
392     
393     /**
394      * Escape a string such that it is safe to use in an XML document.
395      * @param str the string to escape
396      */

397     protected void escapeString(String JavaDoc str) {
398         if ( str == null ) {
399             m_out.print("null");
400             return;
401         }
402         
403         int len = str.length();
404         for (int i = 0; i < len; ++i) {
405             char c = str.charAt(i);
406             
407             if ( (c < LOWER_RANGE && c != VALID_CHARS[0] &&
408                   c != VALID_CHARS[1] && c != VALID_CHARS[2])
409                  || (c > UPPER_RANGE) )
410             {
411                 // character out of range, escape with character value
412
m_out.print("&#");
413                 m_out.print(Integer.toString(c));
414                 m_out.print(';');
415             } else {
416                 boolean valid = true;
417                 // check for invalid characters (e.g., "<", "&", etc)
418
for (int j=INVALID.length-1; j >= 0; --j )
419                 {
420                     if ( INVALID[j] == c) {
421                         valid = false;
422                         m_out.print(VALID[j]);
423                         break;
424                     }
425                 }
426                 // if character is valid, don't escape
427
if (valid) {
428                     m_out.print(c);
429                 }
430             }
431         }
432     }
433     
434 } // end of class XMLWriter
435
Popular Tags