View Javadoc

1   package org.apache.struts2.interceptor.debugging;
2   
3   import java.io.PrintWriter;
4   import java.io.Writer;
5   import java.util.Stack;
6   
7   /***
8    * A simple writer that outputs XML in a pretty-printed indented stream.
9    *
10   * <p>By default, the chars <code><xmp>& < > " ' \r</xmp></code> are escaped and replaced with a suitable XML entity.
11   * To alter this behavior, override the the {@link #writeText(com.thoughtworks.xstream.core.util.QuickWriter, String)}
12   * and {@link #writeAttributeValue(com.thoughtworks.xstream.core.util.QuickWriter, String)} methods.</p>
13   *
14   * <p>This code was taken from the XStream project under the BSD license.</p>
15   *
16   */
17  public class PrettyPrintWriter {
18  
19      private final PrintWriter writer;
20      private final Stack<String> elementStack = new Stack<String>();
21      private final char[] lineIndenter;
22  
23      private boolean tagInProgress;
24      private int depth;
25      private boolean readyForNewLine;
26      private boolean tagIsEmpty;
27      private String newLine;
28  
29      private static final char[] NULL = "&#x0;".toCharArray();
30      private static final char[] AMP = "&amp;".toCharArray();
31      private static final char[] LT = "&lt;".toCharArray();
32      private static final char[] GT = "&gt;".toCharArray();
33      private static final char[] SLASH_R = "&#x0D;".toCharArray();
34      private static final char[] QUOT = "&quot;".toCharArray();
35      private static final char[] APOS = "&apos;".toCharArray();
36      private static final char[] CLOSE = "</".toCharArray();
37  
38      public PrettyPrintWriter(Writer writer, char[] lineIndenter, String newLine) {
39          this.writer = new PrintWriter(writer);
40          this.lineIndenter = lineIndenter;
41          this.newLine = newLine;
42      }
43  
44      public PrettyPrintWriter(Writer writer, char[] lineIndenter) {
45          this(writer, lineIndenter, "\n");
46      }
47  
48      public PrettyPrintWriter(Writer writer, String lineIndenter, String newLine) {
49          this(writer, lineIndenter.toCharArray(), newLine);
50      }
51  
52      public PrettyPrintWriter(Writer writer, String lineIndenter) {
53          this(writer, lineIndenter.toCharArray());
54      }
55  
56      public PrettyPrintWriter(Writer writer) {
57          this(writer, new char[]{' ', ' '});
58      }
59  
60      public void startNode(String name) {
61          tagIsEmpty = false;
62          finishTag();
63          writer.write('<');
64          writer.write(name);
65          elementStack.push(name);
66          tagInProgress = true;
67          depth++;
68          readyForNewLine = true;
69          tagIsEmpty = true;
70      }
71  
72      public void setValue(String text) {
73          readyForNewLine = false;
74          tagIsEmpty = false;
75          finishTag();
76  
77          writeText(writer, text);
78      }
79  
80      public void addAttribute(String key, String value) {
81          writer.write(' ');
82          writer.write(key);
83          writer.write('=');
84          writer.write('\"');
85          writeAttributeValue(writer, value);
86          writer.write('\"');
87      }
88  
89      protected void writeAttributeValue(PrintWriter writer, String text) {
90          writeText(text);
91      }
92  
93      protected void writeText(PrintWriter writer, String text) {
94          writeText(text);
95      }
96  
97      private void writeText(String text) {
98          int length = text.length();
99          for (int i = 0; i < length; i++) {
100             char c = text.charAt(i);
101             switch (c) {
102                 case '\0':
103                     this.writer.write(NULL);
104                     break;
105                 case '&':
106                     this.writer.write(AMP);
107                     break;
108                 case '<':
109                     this.writer.write(LT);
110                     break;
111                 case '>':
112                     this.writer.write(GT);
113                     break;
114                 case '"':
115                     this.writer.write(QUOT);
116                     break;
117                 case '\'':
118                     this.writer.write(APOS);
119                     break;
120                 case '\r':
121                     this.writer.write(SLASH_R);
122                     break;
123                 default:
124                     this.writer.write(c);
125             }
126         }
127     }
128 
129     public void endNode() {
130         depth--;
131         if (tagIsEmpty) {
132             writer.write('/');
133             readyForNewLine = false;
134             finishTag();
135             elementStack.pop();
136         } else {
137             finishTag();
138             writer.write(CLOSE);
139             writer.write((String)elementStack.pop());
140             writer.write('>');
141         }
142         readyForNewLine = true;
143         if (depth == 0 ) {
144             writer.flush();
145         }
146     }
147 
148     private void finishTag() {
149         if (tagInProgress) {
150             writer.write('>');
151         }
152         tagInProgress = false;
153         if (readyForNewLine) {
154             endOfLine();
155         }
156         readyForNewLine = false;
157         tagIsEmpty = false;
158     }
159 
160     protected void endOfLine() {
161         writer.write(newLine);
162         for (int i = 0; i < depth; i++) {
163             writer.write(lineIndenter);
164         }
165     }
166 
167     public void flush() {
168         writer.flush();
169     }
170 
171     public void close() {
172         writer.close();
173     }
174 }