PageRenderTime 105ms CodeModel.GetById 79ms app.highlight 22ms RepoModel.GetById 1ms app.codeStats 0ms

/bundles/plugins-trunk/XML/xml/indent/IndentingTransformerImpl.java

#
Java | 352 lines | 190 code | 106 blank | 56 comment | 34 complexity | c4c6f73a585b1a476de0722feb7087bc MD5 | raw file
  1/*
  2 *  IndentingTransformerImpl.java - Indents XML elements, by adding whitespace where appropriate.
  3 *
  4 *  Copyright (c) 2002, 2003 Robert McKinnon
  5 *
  6 *  This program is free software; you can redistribute it and/or
  7 *  modify it under the terms of the GNU General Public License
  8 *  as published by the Free Software Foundation; either version 2
  9 *  of the License, or any later version.
 10 *
 11 *  This program is distributed in the hope that it will be useful,
 12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14 *  GNU General Public License for more details.
 15 *
 16 *  You should have received a copy of the GNU General Public License
 17 *  along with this program; if not, write to the Free Software
 18 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 19 *
 20 *  email: robmckinnon@users.sourceforge.net
 21 */
 22
 23package xml.indent;
 24
 25import org.xml.sax.Attributes;
 26import org.xml.sax.Locator;
 27import org.xml.sax.SAXException;
 28
 29import javax.xml.transform.Result;
 30import javax.xml.transform.Transformer;
 31import java.util.List;
 32import java.io.Writer;
 33import java.io.IOException;
 34
 35/**
 36 * Indents elements, by adding whitespace where appropriate.
 37 * Does not remove blank lines between nodes.
 38 * Does not remove new lines within text nodes.
 39 * Puts element tags immediately following mixed content text on the same line as the text.
 40 *
 41 * @author Robert McKinnon - robmckinnon@users.sourceforge.net
 42 */
 43public class IndentingTransformerImpl extends IndentingTransformer {
 44
 45  private List preserveWhitespaceList;
 46
 47  /** indent by this many spaces */
 48  private int indentAmount = 2;
 49
 50  /** indent with tabs instead of spaces */
 51  private char indentChar;
 52
 53  /** current indentation level */
 54  private int indentLevel;
 55
 56//  /** true if the previous tag was an element start tag */
 57//  private boolean isStartTagPrevious = false;
 58
 59  /** true if no newlines in element */
 60  private boolean isSameLine;
 61
 62  /** true if last item was non-whitespace text */
 63  private boolean isLastText;
 64
 65  /** true if there is a non-whitespace text item, followed by an element start */
 66  private boolean isMixedContent;
 67
 68  /** true if inside an element configured to have whitespace preserved */
 69  private boolean preserveWhitespace;
 70
 71  /** name of element we are inside that is configured to have whitespace preserved */
 72  private String preserveWhitespaceElement;
 73
 74  /** buffer to hold character data */
 75  private StringBuffer buffer = new StringBuffer();
 76
 77
 78  public String indentXml(String xmlString, Writer outputWriter, int indentAmount, boolean indentWithTabs, List preserveWhitespaceList)
 79      throws IOException, SAXException {
 80    this.preserveWhitespaceList = preserveWhitespaceList;
 81    this.indentAmount = indentAmount;
 82
 83    if(indentWithTabs) {
 84      this.indentChar = '\t';
 85    } else {
 86      this.indentChar = ' ';
 87    }
 88
 89    indentLevel = 0;
 90    isSameLine = false;
 91    isLastText = false;
 92    isMixedContent = false;
 93    preserveWhitespace = false;
 94    preserveWhitespaceElement = null;
 95    buffer.setLength(0);
 96
 97    return super.indentXml(xmlString, outputWriter);
 98  }
 99
100
101  public Transformer getTransformer() {
102    return null;
103  }
104
105
106  public void startElement(String uri, String localName, String qualifiedName, Attributes attributes) throws SAXException {
107    flush();
108
109    if(preserveWhitespaceList.contains(qualifiedName)) {
110      preserveWhitespace = true;
111      preserveWhitespaceElement = qualifiedName;
112    }
113
114    if(isLastText && !isMixedContent) {
115      isMixedContent = true;
116    }
117
118    if(!isMixedContent) {
119      indent(0);
120    }
121
122    super.startElement(uri, localName, qualifiedName, attributes);
123//    isStartTagPrevious = true;
124
125    indentLevel++;
126
127    isSameLine = true; // assume a single line of content
128  }
129
130
131  public void endElement(String uri, String localName, String qualifiedName) throws SAXException {
132//    boolean tempIsLastText = isLastText;
133//    if(isStartTagPrevious) {
134//      isLastText = true;
135//    }
136
137    flush();
138
139//    if(isStartTagPrevious) {
140//      isLastText = tempIsLastText;
141//    }
142
143    indentLevel--;
144
145    if(!isMixedContent && !isSameLine && !isLastText) {
146      indent(0);
147    }
148
149    super.endElement(uri, localName, qualifiedName);
150//    isStartTagPrevious = false;
151    isLastText = false;
152    isSameLine = false;
153    isMixedContent = false;
154
155    if(qualifiedName.equals(preserveWhitespaceElement)) {
156      preserveWhitespace = false;
157      preserveWhitespaceElement = null;
158    }
159  }
160
161
162  public void processingInstruction(String target, String data) throws SAXException {
163    flush();
164    indent(0);
165    super.processingInstruction(target, data);
166  }
167
168
169  public void characters(char[] chars, int start, int length) throws SAXException {
170    for(int i = start; i < start + length; i++) {
171      if(!Character.isWhitespace(chars[i])) {
172        isLastText = true;
173      }
174    }
175
176    if(preserveWhitespace) {
177      isLastText = true;
178    }
179
180    buffer.append(chars, start, length);
181  }
182
183
184  public void comment(char[] chars, int start, int len) throws SAXException {
185    isLastText = true;
186    flush();
187    super.comment(chars, start, len);
188    isLastText = false;
189  }
190
191
192  /**
193   * Output white space to reflect the current indentation level
194   */
195  protected void indent(int levelAdjustment) throws SAXException {
196    int arraySize = (indentLevel + levelAdjustment) * indentAmount + 1;
197    arraySize = arraySize <= 0 ? 1 : arraySize;
198    char[] indent = new char[arraySize];
199    indent[0] = '\n';
200
201    for(int i = 1; i < indent.length; i++) {
202      indent[i] = indentChar;
203    }
204
205    super.characters(indent, 0, indent.length);
206  }
207
208
209  /**
210   * Flush the buffer containing accumulated character data.
211   * White space adjacent to markup is trimmed.
212   */
213  public void flush() throws SAXException {
214    int end = buffer.length();
215    int start = 0;
216
217    if(end != 0) {
218      char[] array = new char[end];
219      buffer.getChars(0, end, array, 0);
220
221      if(!isLastText) {
222
223        boolean stripNewLineFromStart = true;
224
225        while(start < end && Character.isWhitespace(array[start])) {
226          if(Character.isSpaceChar(array[start]) || array[start] == '\t') {
227            start++;
228          } else if(stripNewLineFromStart) {
229            start++;
230            stripNewLineFromStart = false;
231          } else {
232            break;
233          }
234        }
235
236        if(start < end && Character.isWhitespace(array[end - 1])) {
237
238          while(start < end && Character.isWhitespace(array[end - 1])) {
239            if(Character.isSpaceChar(array[end - 1]) || array[start] == '\t') {
240              end--;
241            } else {
242              break;
243            }
244          }
245        }
246
247        for(int i = start; i < end; i++) {
248          if(array[i] == '\n') {
249            isSameLine = false;
250            break;
251          }
252        }
253      }
254
255      super.characters(array, start, end - start);
256      buffer.setLength(0);
257    }
258
259  }
260
261
262  public void setDocumentLocator(Locator locator) {
263  }
264
265
266  public void startCDATA() throws SAXException {
267    isLastText = true;
268    flush();
269  }
270
271
272  public void notationDecl(String name, String publicId, String systemId) throws SAXException {
273  }
274
275
276  public void setSystemId(String systemID) {
277  }
278
279
280  public void startDocument() throws SAXException {
281  }
282
283
284  public void endCDATA() throws SAXException {
285  }
286
287
288  public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException {
289  }
290
291
292  public String getSystemId() {
293    return null;
294  }
295
296
297  public void endDocument() throws SAXException {
298  }
299
300
301  public void startPrefixMapping(String prefix, String uri) throws SAXException {
302  }
303
304
305  public void endPrefixMapping(String prefix) throws SAXException {
306  }
307
308
309  public void skippedEntity(String name) throws SAXException {
310  }
311
312
313  public void setResult(Result result) throws IllegalArgumentException {
314  }
315
316
317  public void ignorableWhitespace(char[] chars, int i, int i1) throws SAXException {
318  }
319
320
321  public void endDTD() throws SAXException {
322  }
323
324
325  public void attributeDecl(String s, String s1, String s2, String s3, String s4) throws SAXException {
326  }
327
328
329  public void endEntity(String s) throws SAXException {
330  }
331
332
333  public void elementDecl(String s, String s1) throws SAXException {
334  }
335
336
337  public void startDTD(String s, String s1, String s2) throws SAXException {
338  }
339
340
341  public void externalEntityDecl(String s, String s1, String s2) throws SAXException {
342  }
343
344
345  public void startEntity(String s) throws SAXException {
346  }
347
348
349  public void internalEntityDecl(String s, String s1) throws SAXException {
350  }
351
352}