001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.xml.serialize;
019:
020: import java.io.Writer;
021: import java.io.StringWriter;
022: import java.io.IOException;
023:
024: /**
025: * Extends {@link Printer} and adds support for indentation and line
026: * wrapping.
027: *
028: * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended
029: * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation
030: * API for XML (TrAX) for serializing XML. See the Xerces documentation for more
031: * information.
032: * @version $Revision: 476047 $ $Date: 2006-11-16 23:27:45 -0500 (Thu, 16 Nov 2006) $
033: * @author <a href="mailto:arkin@intalio.com">Assaf Arkin</a>
034: */
035: public class IndentPrinter extends Printer {
036:
037: /**
038: * Holds the currently accumulating text line. This buffer will constantly
039: * be reused by deleting its contents instead of reallocating it.
040: */
041: private StringBuffer _line;
042:
043: /**
044: * Holds the currently accumulating text that follows {@link #_line}.
045: * When the end of the part is identified by a call to {@link #printSpace}
046: * or {@link #breakLine}, this part is added to the accumulated line.
047: */
048: private StringBuffer _text;
049:
050: /**
051: * Counts how many white spaces come between the accumulated line and the
052: * current accumulated text. Multiple spaces at the end of the a line
053: * will not be printed.
054: */
055: private int _spaces;
056:
057: /**
058: * Holds the indentation for the current line that is now accumulating in
059: * memory and will be sent for printing shortly.
060: */
061: private int _this Indent;
062:
063: /**
064: * Holds the indentation for the next line to be printed. After this line is
065: * printed, {@link #_nextIndent} is assigned to {@link #_thisIndent}.
066: */
067: private int _nextIndent;
068:
069: public IndentPrinter(Writer writer, OutputFormat format) {
070: super (writer, format);
071: // Initialize everything for a first/second run.
072: _line = new StringBuffer(80);
073: _text = new StringBuffer(20);
074: _spaces = 0;
075: _this Indent = _nextIndent = 0;
076: }
077:
078: /**
079: * Called by any of the DTD handlers to enter DTD mode.
080: * Once entered, all output will be accumulated in a string
081: * that can be printed as part of the document's DTD.
082: * This method may be called any number of time but will only
083: * have affect the first time it's called. To exist DTD state
084: * and get the accumulated DTD, call {@link #leaveDTD}.
085: */
086: public void enterDTD() {
087: // Can only enter DTD state once. Once we're out of DTD
088: // state, can no longer re-enter it.
089: if (_dtdWriter == null) {
090: _line.append(_text);
091: _text = new StringBuffer(20);
092: flushLine(false);
093: _dtdWriter = new StringWriter();
094: _docWriter = _writer;
095: _writer = _dtdWriter;
096: }
097: }
098:
099: /**
100: * Called by the root element to leave DTD mode and if any
101: * DTD parts were printer, will return a string with their
102: * textual content.
103: */
104: public String leaveDTD() {
105: // Only works if we're going out of DTD mode.
106: if (_writer == _dtdWriter) {
107: _line.append(_text);
108: _text = new StringBuffer(20);
109: flushLine(false);
110: _writer = _docWriter;
111: return _dtdWriter.toString();
112: }
113: return null;
114: }
115:
116: /**
117: * Called to print additional text. Each time this method is called
118: * it accumulates more text. When a space is printed ({@link
119: * #printSpace}) all the accumulated text becomes one part and is
120: * added to the accumulate line. When a line is long enough, it can
121: * be broken at its text boundary.
122: *
123: * @param text The text to print
124: */
125: public void printText(String text) {
126: _text.append(text);
127: }
128:
129: public void printText(StringBuffer text) {
130: _text.append(text.toString());
131: }
132:
133: public void printText(char ch) {
134: _text.append(ch);
135: }
136:
137: public void printText(char[] chars, int start, int length) {
138: _text.append(chars, start, length);
139: }
140:
141: /**
142: * Called to print a single space between text parts that may be
143: * broken into separate lines. Must not be called to print a space
144: * when preserving spaces. The text accumulated so far with {@link
145: * #printText} will be added to the accumulated line, and a space
146: * separator will be counted. If the line accumulated so far is
147: * long enough, it will be printed.
148: */
149: public void printSpace() {
150: // The line consists of the text accumulated in _line,
151: // followed by one or more spaces as counted by _spaces,
152: // followed by more space accumulated in _text:
153: // - Text is printed and accumulated into _text.
154: // - A space is printed, so _text is added to _line and
155: // a space is counted.
156: // - More text is printed and accumulated into _text.
157: // - A space is printed, the previous spaces are added
158: // to _line, the _text is added to _line, and a new
159: // space is counted.
160:
161: // If text was accumulated with printText(), then the space
162: // means we have to move that text into the line and
163: // start accumulating new text with printText().
164: if (_text.length() > 0) {
165: // If the text breaks a line bounary, wrap to the next line.
166: // The printed line size consists of the indentation we're going
167: // to use next, the accumulated line so far, some spaces and the
168: // accumulated text so far.
169: if (_format.getLineWidth() > 0
170: && _this Indent + _line.length() + _spaces
171: + _text.length() > _format.getLineWidth()) {
172: flushLine(false);
173: try {
174: // Print line and new line, then zero the line contents.
175: _writer.write(_format.getLineSeparator());
176: } catch (IOException except) {
177: // We don't throw an exception, but hold it
178: // until the end of the document.
179: if (_exception == null)
180: _exception = except;
181: }
182: }
183:
184: // Add as many spaces as we accumulaed before.
185: // At the end of this loop, _spaces is zero.
186: while (_spaces > 0) {
187: _line.append(' ');
188: --_spaces;
189: }
190: _line.append(_text);
191: _text = new StringBuffer(20);
192: }
193: // Starting a new word: accumulate the text between the line
194: // and this new word; not a new word: just add another space.
195: ++_spaces;
196: }
197:
198: /**
199: * Called to print a line consisting of the text accumulated so
200: * far. This is equivalent to calling {@link #printSpace} but
201: * forcing the line to print and starting a new line ({@link
202: * #printSpace} will only start a new line if the current line
203: * is long enough).
204: */
205: public void breakLine() {
206: breakLine(false);
207: }
208:
209: public void breakLine(boolean preserveSpace) {
210: // Equivalent to calling printSpace and forcing a flushLine.
211: if (_text.length() > 0) {
212: while (_spaces > 0) {
213: _line.append(' ');
214: --_spaces;
215: }
216: _line.append(_text);
217: _text = new StringBuffer(20);
218: }
219: flushLine(preserveSpace);
220: try {
221: // Print line and new line, then zero the line contents.
222: _writer.write(_format.getLineSeparator());
223: } catch (IOException except) {
224: // We don't throw an exception, but hold it
225: // until the end of the document.
226: if (_exception == null)
227: _exception = except;
228: }
229: }
230:
231: /**
232: * Flushes the line accumulated so far to the writer and get ready
233: * to accumulate the next line. This method is called by {@link
234: * #printText} and {@link #printSpace} when the accumulated line plus
235: * accumulated text are two long to fit on a given line. At the end of
236: * this method _line is empty and _spaces is zero.
237: */
238: public void flushLine(boolean preserveSpace) {
239: int indent;
240:
241: if (_line.length() > 0) {
242: try {
243:
244: if (_format.getIndenting() && !preserveSpace) {
245: // Make sure the indentation does not blow us away.
246: indent = _this Indent;
247: if ((2 * indent) > _format.getLineWidth()
248: && _format.getLineWidth() > 0)
249: indent = _format.getLineWidth() / 2;
250: // Print the indentation as spaces and set the current
251: // indentation to the next expected indentation.
252: while (indent > 0) {
253: _writer.write(' ');
254: --indent;
255: }
256: }
257: _this Indent = _nextIndent;
258:
259: // There is no need to print the spaces at the end of the line,
260: // they are simply stripped and replaced with a single line
261: // separator.
262: _spaces = 0;
263: _writer.write(_line.toString());
264:
265: _line = new StringBuffer(40);
266: } catch (IOException except) {
267: // We don't throw an exception, but hold it
268: // until the end of the document.
269: if (_exception == null)
270: _exception = except;
271: }
272: }
273: }
274:
275: /**
276: * Flush the output stream. Must be called when done printing
277: * the document, otherwise some text might be buffered.
278: */
279: public void flush() {
280: if (_line.length() > 0 || _text.length() > 0)
281: breakLine();
282: try {
283: _writer.flush();
284: } catch (IOException except) {
285: // We don't throw an exception, but hold it
286: // until the end of the document.
287: if (_exception == null)
288: _exception = except;
289: }
290: }
291:
292: /**
293: * Increment the indentation for the next line.
294: */
295: public void indent() {
296: _nextIndent += _format.getIndent();
297: }
298:
299: /**
300: * Decrement the indentation for the next line.
301: */
302: public void unindent() {
303: _nextIndent -= _format.getIndent();
304: if (_nextIndent < 0)
305: _nextIndent = 0;
306: // If there is no current line and we're de-identing then
307: // this indentation level is actually the next level.
308: if ((_line.length() + _spaces + _text.length()) == 0)
309: _this Indent = _nextIndent;
310: }
311:
312: public int getNextIndent() {
313: return _nextIndent;
314: }
315:
316: public void setNextIndent(int indent) {
317: _nextIndent = indent;
318: }
319:
320: public void setThisIndent(int indent) {
321: _thisIndent = indent;
322: }
323:
324: }
|