1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.codehaus.mojo.ounce.core;
28
29 import org.w3c.dom.*;
30
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.io.OutputStreamWriter;
34 import java.util.ArrayList;
35 import java.util.HashMap;
36
37
38
39
40
41
42 public class XmlWriter
43 {
44
45 public static final String START_ELEMENT = "<";
46
47 public static final String START_CLOSE_ELEMENT = "</";
48
49 public static final String END_CLOSE_ELEMENT = "/>";
50
51 public static final String END_ELEMENT = ">";
52
53 public static final String HEADER_TEXT = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
54
55 public static String RETURN_CHAR = "\n";
56
57 public static final String TAB_CHAR = "\t";
58
59 public static final String QUOTE = "\"";
60
61 public static final String EQUALS = "=";
62
63 public static final String SPACE = " ";
64
65 public static final String WINDOWS_FAMILY = "windows";
66
67 public static final String LINUX_FAMILY = "linux";
68
69 public static final String SOLARIS_FAMILY = "sunos";
70
71 public static final String UNKNOWN_FAMILY = "other";
72
73 public static final String[] OS_FAMILIES = new String[] { WINDOWS_FAMILY, LINUX_FAMILY, SOLARIS_FAMILY };
74
75 private FileOutputStream m_outstream;
76
77 private OutputStreamWriter m_writer;
78
79 private boolean m_formatXml = true;
80
81 private HashMap
82
83 private HashMap
84
85 private String m_tabs = "";
86
87 private boolean m_writeEmptyValues = false;
88
89 private boolean m_defaultToAttributesOnSameLine = false;
90
91 public XmlWriter()
92 {
93 this( true );
94 }
95
96 public XmlWriter( boolean formatXml )
97 {
98 m_formatXml = formatXml;
99 if ( getOsFamily().equals( WINDOWS_FAMILY ) )
100 {
101 RETURN_CHAR = "\r\n";
102 }
103 }
104
105 public void setDefaultToAttributesOnSameLine( boolean value )
106 {
107 m_defaultToAttributesOnSameLine = value;
108 }
109
110 public void setAttributesOnSameLine( String nodeName, boolean attributesOnSameLine )
111 {
112 m_attributesOnSameLine.put( nodeName, new Boolean( attributesOnSameLine ) );
113 }
114
115 public void setAttributeOrder( String nodeName, String[] attributeOrder )
116 {
117 m_attributeOrder.put( nodeName, attributeOrder );
118 }
119
120 public void setWriteEmptyValues( boolean writeEmptyValues )
121 {
122 m_writeEmptyValues = writeEmptyValues;
123 }
124
125 public void saveXmlFile( String filePath, Document xmlDoc )
126 throws IOException
127 {
128 if ( xmlDoc != null )
129 {
130 m_outstream = new FileOutputStream( filePath );
131 m_writer = new OutputStreamWriter( m_outstream, "UTF-8" );
132
133 startXmlDoc();
134
135 Element root = xmlDoc.getDocumentElement();
136
137 writeElement( root );
138
139 endXmlDoc();
140 }
141 }
142
143 private void writeElement( Node element )
144 throws IOException
145 {
146
147 if ( element.getNodeType() != Node.ELEMENT_NODE )
148 {
149
150 return;
151 }
152
153 NamedNodeMap attributeMap = element.getAttributes();
154
155 boolean hasChildren = false;
156
157 NodeList childNodes = element.getChildNodes();
158 for ( int i = 0; i < childNodes.getLength(); i++ )
159 {
160 Node node = childNodes.item( i );
161 if ( node.getNodeType() == Node.ELEMENT_NODE )
162 {
163 hasChildren = true;
164 break;
165 }
166 }
167
168 if ( hasChildren )
169 {
170 openElement( element.getNodeName(), attributeMap );
171
172 for ( int i = 0; i < childNodes.getLength(); i++ )
173 {
174 writeElement( childNodes.item( i ) );
175 }
176
177 closeElement( element.getNodeName() );
178 }
179 else
180 {
181
182
183
184 String value = null;
185 for ( int i = 0; i < childNodes.getLength(); i++ )
186 {
187 Node node = childNodes.item( i );
188 if ( node.getNodeType() == Node.TEXT_NODE )
189 {
190 value = node.getNodeValue();
191 break;
192 }
193 }
194
195 if ( value == null )
196 {
197 addElementNoValue( element.getNodeName(), attributeMap );
198 }
199 else
200 {
201 addElementAndValue( element.getNodeName(), value, attributeMap );
202 }
203 }
204 }
205
206 private void addElementAndValue( String nodeName, String value, NamedNodeMap attributeMap )
207 throws IOException
208 {
209 startWriteLine();
210 writeStartElement( nodeName, attributeMap );
211 m_writer.write( value );
212 writeCloseElement( nodeName );
213 endWriteLine();
214 }
215
216 private void addElementNoValue( String nodeName, NamedNodeMap attributeMap )
217 throws IOException
218 {
219 startWriteLine();
220 writeElementNoValue( nodeName, attributeMap );
221 endWriteLine();
222 }
223
224 private void writeElementNoValue( String nodeName, NamedNodeMap attributeMap )
225 throws IOException
226 {
227 m_writer.write( START_ELEMENT );
228 m_writer.write( nodeName );
229 writeAttributes( nodeName, attributeMap );
230 m_writer.write( END_CLOSE_ELEMENT );
231 }
232
233 private void openElement( String nodeName, NamedNodeMap attributeMap )
234 throws IOException
235 {
236 startWriteLine();
237 writeStartElement( nodeName, attributeMap );
238 endWriteLine();
239 incrementTabs();
240 }
241
242 private void writeStartElement( String nodeName, NamedNodeMap attributeMap )
243 throws IOException
244 {
245 m_writer.write( START_ELEMENT );
246 m_writer.write( nodeName );
247 writeAttributes( nodeName, attributeMap );
248 m_writer.write( END_ELEMENT );
249 }
250
251 private void writeAttributes( String nodeName, NamedNodeMap attributeMap )
252 throws IOException
253 {
254 if ( attributeMap != null )
255 {
256
257 boolean attributesOnSameLine = false;
258
259 if ( m_defaultToAttributesOnSameLine )
260 {
261 attributesOnSameLine = true;
262 }
263
264 if ( m_attributesOnSameLine.get( nodeName ) != null )
265 {
266 attributesOnSameLine = ( (Boolean) m_attributesOnSameLine.get( nodeName ) ).booleanValue();
267 }
268
269 if ( !attributesOnSameLine )
270 {
271 m_writer.write( RETURN_CHAR );
272 incrementTabs();
273 }
274
275 ArrayList
276
277 if ( m_attributeOrder.get( nodeName ) != null )
278 {
279
280 String[] attributeOrder = (String[]) m_attributeOrder.get( nodeName );
281 for ( int i = 0; i < attributeOrder.length; i++ )
282 {
283 Node node = attributeMap.getNamedItem( attributeOrder[i] );
284 attributeList.add( node );
285 }
286 }
287 else
288 {
289 for ( int i = 0; i < attributeMap.getLength(); i++ )
290 {
291 Node node = attributeMap.item( i );
292 attributeList.add( node );
293 }
294 }
295
296 for ( int i = 0; i < attributeList.size(); i++ )
297 {
298
299 Node node = (Node) attributeList.get( i );
300 if ( node != null && node.getNodeValue() != null
301 && ( node.getNodeValue().length() > 0 || m_writeEmptyValues ) )
302 {
303
304 if ( !attributesOnSameLine )
305 {
306 m_writer.write( m_tabs );
307 }
308
309 m_writer.write( SPACE );
310 m_writer.write( node.getNodeName() );
311 m_writer.write( EQUALS );
312 m_writer.write( QUOTE );
313 m_writer.write( safeEncode( node.getNodeValue() ) );
314 m_writer.write( QUOTE );
315
316 if ( !attributesOnSameLine )
317 {
318 m_writer.write( RETURN_CHAR );
319 }
320 }
321 }
322
323 if ( !attributesOnSameLine )
324 {
325 decrementTabs();
326 m_writer.write( m_tabs );
327 }
328 }
329 }
330
331 private void closeElement( String nodeName )
332 throws IOException
333 {
334 decrementTabs();
335 startWriteLine();
336 writeCloseElement( nodeName );
337 endWriteLine();
338 }
339
340 private void writeCloseElement( String nodeName )
341 throws IOException
342 {
343 m_writer.write( START_CLOSE_ELEMENT );
344 m_writer.write( nodeName );
345 m_writer.write( END_ELEMENT );
346 }
347
348 public void startWriteLine()
349 throws IOException
350 {
351 if ( m_formatXml )
352 {
353 m_writer.write( m_tabs );
354 }
355 }
356
357 public void endWriteLine()
358 throws IOException
359 {
360 if ( m_formatXml )
361 {
362 m_writer.write( RETURN_CHAR );
363 }
364 }
365
366 private void startXmlDoc()
367 throws IOException
368 {
369 m_writer.write( HEADER_TEXT );
370 m_writer.write( RETURN_CHAR );
371 }
372
373 private void endXmlDoc()
374 throws IOException
375 {
376 m_writer.flush();
377 m_writer.close();
378 m_outstream.close();
379 }
380
381 private void incrementTabs()
382 {
383 if ( m_formatXml )
384 {
385 m_tabs += TAB_CHAR;
386 }
387 }
388
389 private void decrementTabs()
390 {
391 if ( m_formatXml )
392 {
393 if ( m_tabs.length() >= TAB_CHAR.length() )
394 {
395 m_tabs = m_tabs.substring( TAB_CHAR.length() );
396 }
397 }
398 }
399
400
401
402
403
404
405
406
407
408
409
410 public static String safeEncode( String str )
411 {
412 StringBuffer result = null;
413
414 for ( int i = 0, max = str.length(), delta = 0; i < max; i++ )
415 {
416 char c = str.charAt( i );
417 String replacement = null;
418 if ( c == '&' )
419 {
420 replacement = "&";
421 }
422 else if ( c == '<' )
423 {
424 replacement = "<";
425 }
426 else if ( c == '\r' )
427 {
428 replacement = " ";
429 }
430 else if ( c == '>' )
431 {
432 replacement = ">";
433 }
434 else if ( c == '"' )
435 {
436 replacement = """;
437 }
438 else if ( c == '\'' )
439 {
440 replacement = "'";
441 }
442
443 if ( replacement != null )
444 {
445 if ( result == null )
446 {
447 result = new StringBuffer( str );
448 }
449
450 result.replace( i + delta, i + delta + 1, replacement );
451 delta += ( replacement.length() - 1 );
452 }
453 }
454
455 if ( result == null )
456 {
457 return str;
458 }
459
460 return result.toString();
461 }
462
463
464
465
466 private static String getOsName()
467 {
468 return System.getProperty( "os.name" ).toLowerCase();
469 }
470
471
472
473
474
475
476 public static String getOsFamily()
477 {
478 String osName = getOsName();
479 String familyName = UNKNOWN_FAMILY;
480 for ( int i = 0; i < OS_FAMILIES.length; ++i )
481 {
482 if ( osName.startsWith( OS_FAMILIES[i] ) )
483 {
484 familyName = OS_FAMILIES[i];
485 break;
486 }
487 }
488 return familyName;
489 }
490 }