View Javadoc

1   package org.apache.maven.surefire.util;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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                     // uh-oh!  This character is illegal in XML 1.0!
136                     // http://www.w3.org/TR/1998/REC-xml-19980210#charsets
137                     // we're going to deliberately doubly-XML escape it...
138                     // there's nothing better we can do! :-(
139                     // SUREFIRE-456
140                     sb.append( "&amp;#" ).append( (int) c ).append( ';' );
141                 }
142             }
143             else if ( c == '<' )
144             {
145                 sb.append( "&lt;" );
146             }
147             else if ( c == '>' )
148             {
149                 sb.append( "&gt;" );
150             }
151             else if ( c == '&' )
152             {
153                 sb.append( "&amp;" );
154             }
155             else if ( c == '"' )
156             {
157                 sb.append( "&quot;" );
158             }
159             else if ( c == '\'' )
160             {
161                 sb.append( "&apos;" );
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 }