1 package org.apache.maven.shared.utils.xml;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.PrintWriter;
23 import java.io.Writer;
24 import java.util.LinkedList;
25
26 import org.apache.maven.shared.utils.Os;
27
28
29
30
31 public class PrettyPrintXMLWriter
32 implements XMLWriter
33 {
34 private PrintWriter writer;
35
36 private LinkedList<String> elementStack = new LinkedList<String>();
37
38 private boolean processingElement = false;
39
40 private boolean documentStarted = false;
41
42 private boolean endOnSameLine = false;
43
44 private int depth = 0;
45
46 private String lineIndent;
47
48 private String lineSeparator;
49
50 private String encoding;
51
52 private String docType;
53
54
55
56
57
58 public PrettyPrintXMLWriter( PrintWriter writer, String lineIndent )
59 {
60 this( writer, lineIndent, null, null );
61 }
62
63
64
65
66
67 public PrettyPrintXMLWriter( Writer writer, String lineIndent )
68 {
69 this( new PrintWriter( writer ), lineIndent );
70 }
71
72
73
74
75 public PrettyPrintXMLWriter( PrintWriter writer )
76 {
77 this( writer, null, null );
78 }
79
80
81
82
83 public PrettyPrintXMLWriter( Writer writer )
84 {
85 this( new PrintWriter( writer ) );
86 }
87
88
89
90
91
92
93
94 public PrettyPrintXMLWriter( PrintWriter writer, String lineIndent, String encoding, String doctype )
95 {
96 this( writer, lineIndent, Os.LINE_SEP, encoding, doctype );
97 }
98
99
100
101
102
103
104
105 public PrettyPrintXMLWriter( Writer writer, String lineIndent, String encoding, String doctype )
106 {
107 this( new PrintWriter( writer ), lineIndent, encoding, doctype );
108 }
109
110
111
112
113
114
115 public PrettyPrintXMLWriter( PrintWriter writer, String encoding, String doctype )
116 {
117 this( writer, " ", encoding, doctype );
118 }
119
120
121
122
123
124
125 public PrettyPrintXMLWriter( Writer writer, String encoding, String doctype )
126 {
127 this( new PrintWriter( writer ), encoding, doctype );
128 }
129
130
131
132
133
134
135
136
137 public PrettyPrintXMLWriter( PrintWriter writer, String lineIndent, String lineSeparator, String encoding,
138 String doctype )
139 {
140 this.writer = writer;
141 this.lineIndent = lineIndent;
142 this.lineSeparator = lineSeparator;
143 this.encoding = encoding;
144 this.docType = doctype;
145
146 depth = 0;
147 }
148
149 public void addAttribute( String key, String value )
150 {
151 if ( !processingElement )
152 {
153 throw new IllegalStateException( "currently processing no element" );
154 }
155
156 writer.write( ' ' );
157 writer.write( key );
158 writer.write( '=' );
159 writer.write( XMLEncode.xmlEncodeTextForAttribute( value, '"' ) );
160 }
161
162 public void setEncoding( String encoding )
163 {
164 if ( documentStarted )
165 {
166 throw new IllegalStateException( "Document headers already written!" );
167 }
168
169 this.encoding = encoding;
170 }
171
172 public void setDocType( String docType )
173 {
174 if ( documentStarted )
175 {
176 throw new IllegalStateException( "Document headers already written!" );
177 }
178
179 this.docType = docType;
180 }
181
182 public void setLineSeparator( String lineSeparator )
183 {
184 if ( documentStarted )
185 {
186 throw new IllegalStateException( "Document headers already written!" );
187 }
188
189 this.lineSeparator = lineSeparator;
190 }
191
192 public void setLineIndenter( String lineIndent )
193 {
194 if ( documentStarted )
195 {
196 throw new IllegalStateException( "Document headers already written!" );
197 }
198
199 this.lineIndent = lineIndent;
200 }
201
202 public void startElement( String elementName )
203 {
204 boolean firstLine = ensureDocumentStarted();
205
206 completePreviouslyOpenedElement();
207
208 if ( !firstLine )
209 {
210 newLine();
211 }
212
213 writer.write( '<' );
214 writer.write( elementName );
215
216 processingElement = true;
217 depth++;
218
219 elementStack.addLast( elementName );
220 }
221
222 public void writeText( String text )
223 {
224 ensureDocumentStarted();
225
226 completePreviouslyOpenedElement();
227
228 writer.write( XMLEncode.xmlEncodeText( text ) );
229
230 endOnSameLine = true;
231 }
232
233 public void writeMarkup( String markup )
234 {
235 ensureDocumentStarted();
236
237 completePreviouslyOpenedElement();
238
239 writer.write( markup );
240 }
241
242 public void endElement()
243 {
244 depth--;
245
246 if ( processingElement )
247 {
248
249 writer.write( "/>" );
250
251 elementStack.removeLast();
252 processingElement = false;
253 }
254 else
255 {
256 if ( !endOnSameLine )
257 {
258 newLine();
259 }
260
261
262 writer.write( "</" + elementStack.removeLast() + ">" );
263 }
264
265 endOnSameLine = false;
266 }
267
268
269
270
271
272
273 private boolean ensureDocumentStarted()
274 {
275 if ( !documentStarted )
276 {
277 if ( docType != null || encoding != null )
278 {
279 writeDocumentHeader();
280 }
281
282 documentStarted = true;
283
284 return true;
285 }
286
287 return false;
288 }
289
290 private void writeDocumentHeader()
291 {
292 writer.write( "<?xml version=\"1.0\"" );
293
294 if ( encoding != null )
295 {
296 writer.write( " encoding=\"" + encoding + "\"" );
297 }
298
299 writer.write( "?>" );
300
301 newLine();
302
303 if ( docType != null )
304 {
305 newLine();
306 writer.write( "<!DOCTYPE " + docType + ">" );
307 }
308 }
309
310 private void newLine()
311 {
312 writer.write( lineSeparator );
313
314 for ( int i = 0; i < depth; i++ )
315 {
316 writer.write( lineIndent );
317 }
318 }
319
320 private void completePreviouslyOpenedElement()
321 {
322 if ( processingElement )
323 {
324 writer.write( '>' );
325 processingElement = false;
326 }
327 }
328
329 }