View Javadoc

1   /*
2    * Copyright (c) 2003, Henri Yandell
3    * All rights reserved.
4    * 
5    * Redistribution and use in source and binary forms, with or 
6    * without modification, are permitted provided that the 
7    * following conditions are met:
8    * 
9    * + Redistributions of source code must retain the above copyright notice, 
10   *   this list of conditions and the following disclaimer.
11   * 
12   * + Redistributions in binary form must reproduce the above copyright notice, 
13   *   this list of conditions and the following disclaimer in the documentation 
14   *   and/or other materials provided with the distribution.
15   * 
16   * + Neither the name of XmlWriter nor the names of its contributors 
17   *   may be used to endorse or promote products derived from this software 
18   *   without specific prior written permission.
19   * 
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
23   * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
30   * POSSIBILITY OF SUCH DAMAGE.
31   */
32  package com.generationjava.io.xml;
33  
34  import java.io.IOException;
35  
36  /***
37   * Handles indentation on the fly. 
38   */
39  public class PrettyPrinterXmlWriter extends DelegatingXmlWriter {
40  
41      private boolean empty;      // is the current node empty
42      private boolean closed;     // is the current node closed...
43  
44      private boolean wroteText; // was text the last thing output?
45      private String indent;     // output this to indent one level when pretty printing
46      private String newline;    // output this to end a line when pretty printing
47  
48      private int indentSize;
49  
50      /***
51       * Create an PrettyPrinterXmlWriter on top of an existing XmlWriter.
52       */
53      public PrettyPrinterXmlWriter(XmlWriter xmlWriter) {
54          super(xmlWriter);
55          this.closed = true;
56          this.wroteText = false;
57          this.newline = "\n";
58          this.indent = "  ";
59      }
60  
61      /***
62       * Specify the string to prepend to a line for each level of indent. 
63       * It is 2 spaces ("  ") by default. Some may prefer a single tab ("\t")
64       * or a different number of spaces. Specifying an empty string will turn
65       * off indentation when pretty printing.
66       *
67       * @param String representing one level of indentation while pretty printing.
68       */
69      public XmlWriter setIndent(String indent) {
70          this.indent = indent;
71          return this;
72      }
73  
74      /***
75       * Specify the string used to terminate each line when pretty printing. 
76       * It is a single newline ("\n") by default. Users who need to read
77       * generated XML documents in Windows editors like Notepad may wish to
78       * set this to a carriage return/newline sequence ("\r\n"). Specifying
79       * an empty string will turn off generation of line breaks when pretty
80       * printing.  
81       *
82       * @param String representing the newline sequence when pretty printing.
83       */
84      public XmlWriter setNewline(String newline) {
85          this.newline = newline;
86          return this;
87      }
88  
89      public XmlWriter writeXmlVersion() throws IOException {
90          super.writeXmlVersion();
91          getWriter().write(this.newline);
92          return this;
93      }
94      public XmlWriter writeXmlVersion(String version, String encoding) throws IOException {
95          super.writeXmlVersion(version, encoding);
96          getWriter().write(this.newline);
97          return this;
98      }
99      public XmlWriter writeXmlVersion(String version, String encoding, String standalone) throws IOException {
100         super.writeXmlVersion(version, encoding, standalone);
101         getWriter().write(this.newline);
102         return this;
103     }
104 
105     /***
106      *
107      * @param name String name of tag
108      */
109     public XmlWriter writeEntity(String name) throws IOException {
110 
111         // writeText used instead of getWriter(). This makes the 
112         // whitespace appaer in the right place
113         if ( !this.closed || this.wroteText) {
114             writeText(newline);
115         }
116         for (int i = 0; i < indentSize; i++) {
117             writeText(indent);
118         }
119 
120         super.writeEntity(name);
121         this.closed = false;
122         indentSize++;
123         this.empty = true;
124         this.wroteText = false;
125         return this;
126     }
127 
128     /***
129      * End the current entity. This will throw an exception 
130      * if it is called when there is not a currently open 
131      * entity.
132      */
133     public XmlWriter endEntity() throws IOException {
134         indentSize--;
135         if(!this.empty) {
136             if(!this.wroteText) {
137                 for (int i = 0; i < this.indentSize; i++) {
138                     getWriter().write(indent); // Indent closing tag to proper level
139                 }
140             }
141         }
142         super.endEntity();
143         getWriter().write(newline); 
144         this.empty = false;
145         this.closed = true;
146         this.wroteText = false;
147         return this;
148     }
149 
150     /***
151      * Output body text. Any xml characters are escaped. 
152      */
153     public XmlWriter writeText(Object text) throws IOException {
154         super.writeText(text);
155         this.empty = false;
156         this.wroteText = true;
157         return this;
158     }
159 
160     /***
161      * Write out a chunk of CDATA. This helper method surrounds the 
162      * passed in data with the CDATA tag.
163      *
164      * @param String of CDATA text.
165      */
166     public XmlWriter writeCData(String cdata) throws IOException {
167 //        indentChunk();
168         super.writeCData(cdata);
169 //        getWriter().write(newline); 
170         this.empty = false;
171         this.wroteText = true;
172         return this;
173     }
174 
175     /***
176      * Write out a chunk of comment. This helper method surrounds the 
177      * passed in data with the xml comment tag.
178      *
179      * @param String of text to comment.
180      */
181     public XmlWriter writeComment(String comment) throws IOException {
182         indentChunk();
183         if(!comment.startsWith(" ")) {
184             comment = " "+comment;
185         }
186         if(!comment.endsWith(" ")) {
187             comment = comment+" ";
188         }
189         super.writeComment(comment);
190         getWriter().write(newline); 
191         return this;
192     }
193 
194     /***
195      * A helper method. It writes out an entity which contains only text.
196      *
197      * @param name String name of tag
198      * @param text String of text to go inside the tag
199      */
200     public XmlWriter writeEntityWithText(String name, Object text)
201                      throws IOException {
202         indentChunk();
203         super.writeEntityWithText(name, text);
204         getWriter().write(newline);
205         return this;
206     }
207 
208     /***
209      * A helper method. It writes out empty entities.
210      *
211      * @param name String name of tag
212      */
213     public XmlWriter writeEmptyEntity(String name) throws IOException {
214         indentChunk();
215         super.writeEmptyEntity(name);
216         getWriter().write(newline);
217         return this;
218     }
219 
220     private void indentChunk() throws IOException {
221         this.empty = false;
222         if(!this.wroteText) {
223             for (int i = 0; i < this.indentSize; i++) {
224                 getWriter().write(indent); 
225             }
226         }
227     }
228 
229 }