View Javadoc
1   package org.apache.maven.plugin.surefire.report;
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 java.io.PrintWriter;
23  import java.util.LinkedList;
24  
25  import org.apache.maven.shared.utils.xml.XMLWriter;
26  
27  /**
28   * A pretty printing XML writer
29   *
30   */
31  public class PrettyPrintXMLWriter
32      implements XMLWriter
33  {
34      private final PrintWriter writer;
35  
36      private final LinkedList<String> elementStack = new LinkedList<String>();
37  
38      private boolean tagInProgress;
39  
40      private int depth;
41  
42      private final String lineIndenter;
43  
44      private final String encoding;
45  
46      private final String docType;
47  
48      private boolean readyForNewLine;
49  
50      private boolean tagIsEmpty;
51  
52      public PrettyPrintXMLWriter( PrintWriter writer )
53      {
54          this( writer, null, null );
55      }
56  
57      private PrettyPrintXMLWriter( PrintWriter writer, String lineIndenter, String encoding, String doctype )
58      {
59          this.writer = writer;
60  
61          this.lineIndenter = lineIndenter;
62  
63          this.encoding = encoding;
64  
65          this.docType = doctype;
66  
67          if ( docType != null || encoding != null )
68          {
69              writeDocumentHeaders();
70          }
71      }
72  
73      public void setEncoding( String encoding )
74      {
75          throw new RuntimeException( "Not Implemented" );
76      }
77  
78      public void setDocType( String docType )
79      {
80          throw new RuntimeException( "Not Implemented" );
81      }
82  
83      private PrettyPrintXMLWriter( PrintWriter writer, String encoding, String doctype )
84      {
85          this( writer, "  ", encoding, doctype );
86      }
87  
88      public void startElement( String name )
89      {
90          tagIsEmpty = false;
91  
92          finishTag();
93  
94          write( "<" );
95  
96          write( name );
97  
98          elementStack.addLast( name );
99  
100         tagInProgress = true;
101 
102         depth++;
103 
104         readyForNewLine = true;
105 
106         tagIsEmpty = true;
107     }
108 
109     public void writeText( String text )
110     {
111         writeText( text, true );
112     }
113 
114     public void writeMarkup( String text )
115     {
116         writeText( text, false );
117     }
118 
119     private void writeText( String text, boolean escapeXml )
120     {
121         readyForNewLine = false;
122 
123         tagIsEmpty = false;
124 
125         finishTag();
126 
127         if ( escapeXml )
128         {
129             text = escapeXml( text );
130         }
131 
132         write( text );
133     }
134 
135     private static String escapeXml( String text )
136     {
137         StringBuffer sb = new StringBuffer( text.length() * 2 );
138         for ( int i = 0; i < text.length(); i++ )
139         {
140             char c = text.charAt( i );
141             if ( c < 32 )
142             {
143                 if ( c == '\n' || c == '\r' || c == '\t' )
144                 {
145                     sb.append( c );
146                 }
147                 else
148                 {
149                     // uh-oh!  This character is illegal in XML 1.0!
150                     // http://www.w3.org/TR/1998/REC-xml-19980210#charsets
151                     // we're going to deliberately doubly-XML escape it...
152                     // there's nothing better we can do! :-(
153                     // SUREFIRE-456
154                     sb.append( "&amp;#" ).append( (int) c ).append( ';' );
155                 }
156             }
157             else if ( c == '<' )
158             {
159                 sb.append( "&lt;" );
160             }
161             else if ( c == '>' )
162             {
163                 sb.append( "&gt;" );
164             }
165             else if ( c == '&' )
166             {
167                 sb.append( "&amp;" );
168             }
169             else if ( c == '"' )
170             {
171                 sb.append( "&quot;" );
172             }
173             else if ( c == '\'' )
174             {
175                 sb.append( "&apos;" );
176             }
177             else
178             {
179                 sb.append( c );
180             }
181         }
182         return sb.toString();
183     }
184 
185     public void addAttribute( String key, String value )
186     {
187         write( " " );
188 
189         write( key );
190 
191         write( "=\"" );
192 
193         write( escapeXml( value ) );
194 
195         write( "\"" );
196     }
197 
198     public void endElement()
199     {
200         depth--;
201 
202         if ( tagIsEmpty )
203         {
204             write( "/" );
205 
206             readyForNewLine = false;
207 
208             finishTag();
209 
210             elementStack.removeLast();
211         }
212         else
213         {
214             finishTag();
215 
216             write( "</" + elementStack.removeLast() + ">" );
217         }
218 
219         readyForNewLine = true;
220     }
221 
222     private void write( String str )
223     {
224         writer.write( str );
225     }
226 
227     private void finishTag()
228     {
229         if ( tagInProgress )
230         {
231             write( ">" );
232         }
233 
234         tagInProgress = false;
235 
236         if ( readyForNewLine )
237         {
238             endOfLine();
239         }
240         readyForNewLine = false;
241 
242         tagIsEmpty = false;
243     }
244 
245     protected void endOfLine()
246     {
247         write( "\n" );
248 
249         for ( int i = 0; i < depth; i++ )
250         {
251             write( lineIndenter );
252         }
253     }
254 
255     private void writeDocumentHeaders()
256     {
257         write( "<?xml version=\"1.0\"" );
258 
259         if ( encoding != null )
260         {
261             write( " encoding=\"" + encoding + "\"" );
262         }
263 
264         write( "?>" );
265 
266         endOfLine();
267 
268         if ( docType != null )
269         {
270             write( "<!DOCTYPE " );
271 
272             write( docType );
273 
274             write( ">" );
275 
276             endOfLine();
277         }
278     }
279 }