1 package org.apache.maven.surefire.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.codehaus.plexus.util.xml.XMLWriter;
23
24 import java.io.PrintWriter;
25 import java.util.LinkedList;
26
27 public class PrettyPrintXMLWriter
28 implements XMLWriter
29 {
30 private final PrintWriter writer;
31
32 private final LinkedList elementStack = new LinkedList();
33
34 private boolean tagInProgress;
35
36 private int depth;
37
38 private final String lineIndenter;
39
40 private final String encoding;
41
42 private final String docType;
43
44 private boolean readyForNewLine;
45
46 private boolean tagIsEmpty;
47
48 public PrettyPrintXMLWriter( PrintWriter writer )
49 {
50 this( writer, null, null );
51 }
52
53 private PrettyPrintXMLWriter( PrintWriter writer, String lineIndenter, String encoding, String doctype )
54 {
55 this.writer = writer;
56
57 this.lineIndenter = lineIndenter;
58
59 this.encoding = encoding;
60
61 this.docType = doctype;
62
63 if ( docType != null || encoding != null )
64 {
65 writeDocumentHeaders();
66 }
67 }
68
69 private PrettyPrintXMLWriter( PrintWriter writer, String encoding, String doctype )
70 {
71 this( writer, " ", encoding, doctype );
72 }
73
74 public void startElement( String name )
75 {
76 tagIsEmpty = false;
77
78 finishTag();
79
80 write( "<" );
81
82 write( name );
83
84 elementStack.addLast( name );
85
86 tagInProgress = true;
87
88 depth++;
89
90 readyForNewLine = true;
91
92 tagIsEmpty = true;
93 }
94
95 public void writeText( String text )
96 {
97 writeText( text, true );
98 }
99
100 public void writeMarkup( String text )
101 {
102 writeText( text, false );
103 }
104
105 private void writeText( String text, boolean escapeXml )
106 {
107 readyForNewLine = false;
108
109 tagIsEmpty = false;
110
111 finishTag();
112
113 if ( escapeXml )
114 {
115 text = escapeXml( text );
116 }
117
118 write( text );
119 }
120
121 private static String escapeXml( String text )
122 {
123 StringBuffer sb = new StringBuffer ( text.length() * 2 );
124 for ( int i = 0; i < text.length(); i++ )
125 {
126 char c = text.charAt( i );
127 if ( c < 32 )
128 {
129 if ( c == '\n' || c == '\r' || c == '\t' )
130 {
131 sb.append( c );
132 }
133 else
134 {
135
136
137
138
139
140 sb.append( "&#" ).append( (int) c ).append( ';' );
141 }
142 }
143 else if ( c == '<' )
144 {
145 sb.append( "<" );
146 }
147 else if ( c == '>' )
148 {
149 sb.append( ">" );
150 }
151 else if ( c == '&' )
152 {
153 sb.append( "&" );
154 }
155 else if ( c == '"' )
156 {
157 sb.append( """ );
158 }
159 else if ( c == '\'' )
160 {
161 sb.append( "'" );
162 }
163 else
164 {
165 sb.append( c );
166 }
167 }
168 return sb.toString();
169 }
170
171 public void addAttribute( String key, String value )
172 {
173 write( " " );
174
175 write( key );
176
177 write( "=\"" );
178
179 write( escapeXml( value ) );
180
181 write( "\"" );
182 }
183
184 public void endElement()
185 {
186 depth--;
187
188 if ( tagIsEmpty )
189 {
190 write( "/" );
191
192 readyForNewLine = false;
193
194 finishTag();
195
196 elementStack.removeLast();
197 }
198 else
199 {
200 finishTag();
201
202 write( "</" + elementStack.removeLast() + ">" );
203 }
204
205 readyForNewLine = true;
206 }
207
208 private void write( String str )
209 {
210 writer.write( str );
211 }
212
213 private void finishTag()
214 {
215 if ( tagInProgress )
216 {
217 write( ">" );
218 }
219
220 tagInProgress = false;
221
222 if ( readyForNewLine )
223 {
224 endOfLine();
225 }
226 readyForNewLine = false;
227
228 tagIsEmpty = false;
229 }
230
231 protected void endOfLine()
232 {
233 write( "\n" );
234
235 for ( int i = 0; i < depth; i++ )
236 {
237 write( lineIndenter );
238 }
239 }
240
241 private void writeDocumentHeaders()
242 {
243 write( "<?xml version=\"1.0\"" );
244
245 if ( encoding != null )
246 {
247 write( " encoding=\"" + encoding + "\"" );
248 }
249
250 write( "?>" );
251
252 endOfLine();
253
254 if ( docType != null )
255 {
256 write( "<!DOCTYPE " );
257
258 write( docType );
259
260 write( ">" );
261
262 endOfLine();
263 }
264 }
265 }