KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jahia > utils > xml > XmlWriter


1 package org.jahia.utils.xml;
2
3 /* ====================================================================
4  * The Apache Software License, Version 1.1
5  *
6  * Copyright (c) 2001 The Apache Software Foundation. All rights
7  * reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution,
22  * if any, must include the following acknowledgment:
23  * "This product includes software developed by the
24  * Apache Software Foundation (http://www.apache.org/)."
25  * Alternately, this acknowledgment may appear in the software itself,
26  * if and wherever such third-party acknowledgments normally appear.
27  *
28  * 4. The names "Apache" and "Apache Software Foundation" and
29  * "Apache Commons" must not be used to endorse or promote products
30  * derived from this software without prior written permission. For
31  * written permission, please contact apache@apache.org.
32  *
33  * 5. Products derived from this software may not be called "Apache",
34  * "Apache Turbine", nor may "Apache" appear in their name, without
35  * prior written permission of the Apache Software Foundation.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals on behalf of the Apache Software Foundation. For more
53  * information on the Apache Software Foundation, please see
54  * <http://www.apache.org/>.
55  */

56
57 import java.io.IOException JavaDoc;
58 import java.io.Writer JavaDoc;
59 import java.util.Stack JavaDoc;
60
61 /**
62  * Makes writing XML much much easier.
63  * Improved from
64  * <a HREF="http://builder.com.com/article.jhtml?id=u00220020318yan01.htm&page=1&vf=tt">article</a>
65  *
66  * @author <a HREF="mailto:bayard@apache.org">Henri Yandell</a>
67  * @author <a HREF="mailto:pete@fingertipsoft.com">Peter Cassetta</a>
68  * @version 1.0
69  */

70 public class XmlWriter {
71
72     private Writer JavaDoc writer; // underlying writer
73
private Stack JavaDoc stack; // of xml entity names
74
private StringBuffer JavaDoc attrs; // current attribute string
75
private boolean empty; // is the current node empty
76
private boolean closed; // is the current node closed...
77

78     private String JavaDoc namespace; // the current default namespace
79

80     private boolean pretty; // is pretty printing enabled?
81
private boolean wroteText; // was text the last thing output?
82
private String JavaDoc indent; // output this to indent one level when pretty printing
83
private String JavaDoc newline; // output this to end a line when pretty printing
84

85     /**
86      * Create an XmlWriter on top of an existing java.io.Writer.
87      */

88     public XmlWriter(Writer JavaDoc writer) {
89         this.writer = writer;
90         this.closed = true;
91         this.stack = new Stack JavaDoc();
92         this.pretty = true;
93         this.wroteText = false;
94         this.newline = "\n";
95         this.indent = " ";
96     }
97
98     /**
99      * Turn pretty printing on or off.
100      * Pretty printing is enabled by default, but it can be turned off
101      * to generate more compact XML.
102      *
103      * @param boolean true to enable, false to disable pretty printing.
104      */

105     public void enablePrettyPrint(boolean enable) {
106         this.pretty = enable;
107     }
108
109     /**
110      * Specify the string to prepend to a line for each level of indent.
111      * It is 2 spaces (" ") by default. Some may prefer a single tab ("\t")
112      * or a different number of spaces. Specifying an empty string will turn
113      * off indentation when pretty printing.
114      *
115      * @param String representing one level of indentation while pretty printing.
116      */

117     public void setIndent(String JavaDoc indent) {
118         this.indent = indent;
119     }
120
121     /**
122      * Specify the string used to terminate each line when pretty printing.
123      * It is a single newline ("\n") by default. Users who need to read
124      * generated XML documents in Windows editors like Notepad may wish to
125      * set this to a carriage return/newline sequence ("\r\n"). Specifying
126      * an empty string will turn off generation of line breaks when pretty
127      * printing.
128      *
129      * @param String representing the newline sequence when pretty printing.
130      */

131     public void setNewline(String JavaDoc newline) {
132         this.newline = newline;
133     }
134
135     /**
136      * The default namespace. Once this is turned on, any new entities
137      * will have this namespace, regardless of scope.
138      *
139      * @param String nname of the namespace
140      */

141     public void setDefaultNamespace(String JavaDoc namespace) {
142         this.namespace = namespace;
143     }
144
145     /**
146      * A helper method. It writes out an entity which contains only text.
147      *
148      * @param name String name of tag
149      * @param text String of text to go inside the tag
150      */

151     public XmlWriter writeEntityWithText(String JavaDoc name, String JavaDoc text) throws IOException JavaDoc {
152         writeEntity(name);
153         writeText(text);
154         return endEntity();
155     }
156
157     /**
158      * A helper method. It writes out empty entities.
159      *
160      * @param name String name of tag
161      */

162     public XmlWriter writeEmptyEntity(String JavaDoc name) throws IOException JavaDoc {
163         writeEntity(name);
164         return endEntity();
165     }
166
167     /**
168      * Begin to write out an entity. Unlike the helper tags, this tag
169      * will need to be ended with the endEntity method.
170      *
171      * @param name String name of tag
172      */

173     public XmlWriter writeEntity(String JavaDoc name) throws IOException JavaDoc {
174         if(this.namespace == null) {
175             return openEntity(name);
176         } else {
177             return openEntity(this.namespace+":"+name);
178         }
179     }
180
181     /**
182      * Begin to output an entity.
183      *
184      * @param String name of entity.
185      */

186     private XmlWriter openEntity(String JavaDoc name) throws IOException JavaDoc {
187         boolean wasClosed = this.closed;
188         closeOpeningTag();
189         this.closed = false;
190         if (this.pretty) {
191             // ! wasClosed separates adjacent opening tags by a newline.
192
// this.wroteText makes sure an entity embedded within the text of
193
// its parent entity begins on a new line, indented to the proper
194
// level. This solves only part of the problem of pretty printing
195
// entities which contain both text and child entities.
196
if (! wasClosed || this.wroteText) {
197                 this.writer.write(newline);
198             }
199             for (int i = 0; i < this.stack.size(); i++) {
200                 this.writer.write(indent); // Indent opening tag to proper level
201
}
202         }
203         this.writer.write("<");
204         this.writer.write(name);
205         stack.add(name);
206         this.empty = true;
207         this.wroteText = false;
208         return this;
209     }
210
211     // close off the opening tag
212
private void closeOpeningTag() throws IOException JavaDoc {
213         if (!this.closed) {
214             writeAttributes();
215             this.closed = true;
216             this.writer.write(">");
217         }
218     }
219
220     // write out all current attributes
221
private void writeAttributes() throws IOException JavaDoc {
222         if (this.attrs != null) {
223             this.writer.write(this.attrs.toString());
224             this.attrs.setLength(0);
225             this.empty = false;
226         }
227     }
228
229     /**
230      * Write an attribute out for the current entity.
231      * Any xml characters in the value are escaped.
232      * Currently it does not actually throw the exception, but
233      * the api is set that way for future changes.
234      *
235      * @param String name of attribute.
236      * @param String value of attribute.
237      */

238     public XmlWriter writeAttribute(String JavaDoc attr, String JavaDoc value) throws IOException JavaDoc {
239
240         // maintain api
241
if (false) throw new IOException JavaDoc();
242
243         if (this.attrs == null) {
244             this.attrs = new StringBuffer JavaDoc();
245         }
246         this.attrs.append(" ");
247         this.attrs.append(attr);
248         this.attrs.append("=\"");
249         this.attrs.append(XmlUtils.escapeXml(value));
250         this.attrs.append("\"");
251         return this;
252     }
253
254     /**
255      * End the current entity. This will throw an exception
256      * if it is called when there is not a currently open
257      * entity.
258      */

259     public XmlWriter endEntity() throws IOException JavaDoc {
260         if(this.stack.empty()) {
261             throw new IOException JavaDoc("Called endEntity too many times. ");
262         }
263         String JavaDoc name = (String JavaDoc)this.stack.pop();
264         if (name != null) {
265             if (this.empty) {
266                 writeAttributes();
267                 this.writer.write("/>");
268             } else {
269             if (this.pretty && ! this.wroteText) {
270                 for (int i = 0; i < this.stack.size(); i++) {
271                     this.writer.write(indent); // Indent closing tag to proper level
272
}
273             }
274             this.writer.write("</");
275             this.writer.write(name);
276             this.writer.write(">");
277         }
278         if (this.pretty)
279             this.writer.write(newline); // Add a newline after the closing tag
280
this.empty = false;
281             this.closed = true;
282             this.wroteText = false;
283         }
284         return this;
285     }
286
287     /**
288      * Close this writer. It does not close the underlying
289      * writer, but does throw an exception if there are
290      * as yet unclosed tags.
291      */

292     public void close() throws IOException JavaDoc {
293         if(!this.stack.empty()) {
294             throw new IOException JavaDoc("Tags are not all closed. "+
295                 "Possibly, "+this.stack.pop()+" is unclosed. ");
296         }
297     }
298
299     /**
300      * Output body text. Any xml characters are escaped.
301      */

302     public XmlWriter writeText(String JavaDoc text) throws IOException JavaDoc {
303         closeOpeningTag();
304         this.empty = false;
305         this.wroteText = true;
306         this.writer.write(XmlUtils.escapeXml(text));
307         return this;
308     }
309
310     /**
311      * Write out a chunk of CDATA. This helper method surrounds the
312      * passed in data with the CDATA tag.
313      *
314      * @param String of CDATA text.
315      */

316     public XmlWriter writeCData(String JavaDoc cdata) throws IOException JavaDoc {
317         writeChunk("<![CDATA[ "+cdata+" ]]>");
318         return this;
319     }
320
321     /**
322      * Write out a chunk of comment. This helper method surrounds the
323      * passed in data with the xml comment tag.
324      *
325      * @param String of text to comment.
326      */

327     public XmlWriter writeComment(String JavaDoc comment) throws IOException JavaDoc {
328         writeChunk("<!-- "+comment+" -->");
329         return this;
330     }
331     private void writeChunk(String JavaDoc data) throws IOException JavaDoc {
332         closeOpeningTag();
333         this.empty = false;
334         if (this.pretty && ! this.wroteText) {
335             for (int i = 0; i < this.stack.size(); i++) {
336                 this.writer.write(indent);
337             }
338         }
339         this.writer.write(data);
340         if (this.pretty) {
341             this.writer.write(newline);
342         }
343     }
344
345 }
346
Popular Tags