001: /*
002: * Copyright (c) 2002-2006 by OpenSymphony
003: * All rights reserved.
004: */
005: package com.opensymphony.webwork.interceptor.debugging;
006:
007: import java.io.Writer;
008: import java.io.PrintWriter;
009: import java.util.Stack;
010:
011: /**
012: * A simple writer that outputs XML in a pretty-printed indented stream.
013: *
014: * <p>By default, the chars <code><xmp>& < > " ' \r</xmp></code> are escaped and replaced with a suitable XML entity.
015: */
016: public class PrettyPrintWriter {
017:
018: private final PrintWriter writer;
019: private final Stack elementStack = new Stack();
020: private final char[] lineIndenter;
021:
022: private boolean tagInProgress;
023: private int depth;
024: private boolean readyForNewLine;
025: private boolean tagIsEmpty;
026: private String newLine;
027:
028: private static final char[] NULL = "�".toCharArray();
029: private static final char[] AMP = "&".toCharArray();
030: private static final char[] LT = "<".toCharArray();
031: private static final char[] GT = ">".toCharArray();
032: private static final char[] SLASH_R = "
".toCharArray();
033: private static final char[] QUOT = """.toCharArray();
034: private static final char[] APOS = "'".toCharArray();
035: private static final char[] CLOSE = "</".toCharArray();
036:
037: public PrettyPrintWriter(Writer writer, char[] lineIndenter,
038: String newLine) {
039: this .writer = new PrintWriter(writer);
040: this .lineIndenter = lineIndenter;
041: this .newLine = newLine;
042: }
043:
044: public PrettyPrintWriter(Writer writer, char[] lineIndenter) {
045: this (writer, lineIndenter, "\n");
046: }
047:
048: public PrettyPrintWriter(Writer writer, String lineIndenter,
049: String newLine) {
050: this (writer, lineIndenter.toCharArray(), newLine);
051: }
052:
053: public PrettyPrintWriter(Writer writer, String lineIndenter) {
054: this (writer, lineIndenter.toCharArray());
055: }
056:
057: public PrettyPrintWriter(Writer writer) {
058: this (writer, new char[] { ' ', ' ' });
059: }
060:
061: public void startNode(String name) {
062: tagIsEmpty = false;
063: finishTag();
064: writer.write('<');
065: writer.write(name);
066: elementStack.push(name);
067: tagInProgress = true;
068: depth++;
069: readyForNewLine = true;
070: tagIsEmpty = true;
071: }
072:
073: public void setValue(String text) {
074: readyForNewLine = false;
075: tagIsEmpty = false;
076: finishTag();
077:
078: writeText(writer, text);
079: }
080:
081: public void addAttribute(String key, String value) {
082: writer.write(' ');
083: writer.write(key);
084: writer.write('=');
085: writer.write('\"');
086: writeAttributeValue(writer, value);
087: writer.write('\"');
088: }
089:
090: protected void writeAttributeValue(PrintWriter writer, String text) {
091: writeText(text);
092: }
093:
094: protected void writeText(PrintWriter writer, String text) {
095: writeText(text);
096: }
097:
098: private void writeText(String text) {
099: int length = text.length();
100: for (int i = 0; i < length; i++) {
101: char c = text.charAt(i);
102: switch (c) {
103: case '\0':
104: this .writer.write(NULL);
105: break;
106: case '&':
107: this .writer.write(AMP);
108: break;
109: case '<':
110: this .writer.write(LT);
111: break;
112: case '>':
113: this .writer.write(GT);
114: break;
115: case '"':
116: this .writer.write(QUOT);
117: break;
118: case '\'':
119: this .writer.write(APOS);
120: break;
121: case '\r':
122: this .writer.write(SLASH_R);
123: break;
124: default:
125: this .writer.write(c);
126: }
127: }
128: }
129:
130: public void endNode() {
131: depth--;
132: if (tagIsEmpty) {
133: writer.write('/');
134: readyForNewLine = false;
135: finishTag();
136: elementStack.pop();
137: } else {
138: finishTag();
139: writer.write(CLOSE);
140: writer.write((String) elementStack.pop());
141: writer.write('>');
142: }
143: readyForNewLine = true;
144: if (depth == 0) {
145: writer.flush();
146: }
147: }
148:
149: private void finishTag() {
150: if (tagInProgress) {
151: writer.write('>');
152: }
153: tagInProgress = false;
154: if (readyForNewLine) {
155: endOfLine();
156: }
157: readyForNewLine = false;
158: tagIsEmpty = false;
159: }
160:
161: protected void endOfLine() {
162: writer.write(newLine);
163: for (int i = 0; i < depth; i++) {
164: writer.write(lineIndenter);
165: }
166: }
167:
168: public void flush() {
169: writer.flush();
170: }
171:
172: public void close() {
173: writer.close();
174: }
175: }
|