001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: //@@3RD PARTY CODE@@
038: // DataWriter.java - XML writer for data-oriented files.
039: package com.sun.xml.bind.marshaller;
040:
041: import java.io.IOException;
042: import java.io.Writer;
043: import java.util.Stack;
044:
045: import org.xml.sax.Attributes;
046: import org.xml.sax.SAXException;
047:
048: /**
049: * Write data- or field-oriented XML.
050: *
051: * <p>This filter pretty-prints field-oriented XML without mixed content.
052: * all added indentation and newlines will be passed on down
053: * the filter chain (if any).</p>
054: *
055: * <p>In general, all whitespace in an XML document is potentially
056: * significant, so a general-purpose XML writing tool like the
057: * {@link XMLWriter} class cannot
058: * add newlines or indentation.</p>
059: *
060: * <p>There is, however, a large class of XML documents where information
061: * is strictly fielded: each element contains either character data
062: * or other elements, but not both. For this special case, it is possible
063: * for a writing tool to provide automatic indentation and newlines
064: * without requiring extra work from the user. Note that this class
065: * will likely not yield appropriate results for document-oriented
066: * XML like XHTML pages, which mix character data and elements together.</p>
067: *
068: * <p>This writer will automatically place each start tag on a new line,
069: * optionally indented if an indent step is provided (by default, there
070: * is no indentation). If an element contains other elements, the end
071: * tag will also appear on a new line with leading indentation. Consider,
072: * for example, the following code:</p>
073: *
074: * <pre>
075: * DataWriter w = new DataWriter();
076: *
077: * w.setIndentStep(2);
078: * w.startDocument();
079: * w.startElement("Person");
080: * w.dataElement("name", "Jane Smith");
081: * w.dataElement("date-of-birth", "1965-05-23");
082: * w.dataElement("citizenship", "US");
083: * w.endElement("Person");
084: * w.endDocument();
085: * </pre>
086: *
087: * <p>This code will produce the following document:</p>
088: *
089: * <pre>
090: * <?xml version="1.0" standalone="yes"?>
091: *
092: * <Person>
093: * <name>Jane Smith</name>
094: * <date-of-birth>1965-05-23</date-of-birth>
095: * <citizenship>US</citizenship>
096: * </Person>
097: * </pre>
098: *
099: * <p>This class inherits from {@link XMLWriter},
100: * and provides all of the same support for Namespaces.</p>
101: *
102: * @since 1.0
103: * @author David Megginson, david@megginson.com
104: * @version 0.2
105: * @see XMLWriter
106: */
107: public class DataWriter extends XMLWriter {
108:
109: ////////////////////////////////////////////////////////////////////
110: // Constructors.
111: ////////////////////////////////////////////////////////////////////
112:
113: /**
114: * Create a new data writer for the specified output.
115: *
116: * @param writer The character stream where the XML document
117: * will be written.
118: * @param encoding
119: * If non-null string is specified, it is written as a part
120: * of the XML declaration.
121: */
122: public DataWriter(Writer writer, String encoding,
123: CharacterEscapeHandler _escapeHandler) {
124: super (writer, encoding, _escapeHandler);
125: }
126:
127: public DataWriter(Writer writer, String encoding) {
128: this (writer, encoding, DumbEscapeHandler.theInstance);
129: }
130:
131: ////////////////////////////////////////////////////////////////////
132: // Accessors and setters.
133: ////////////////////////////////////////////////////////////////////
134:
135: /**
136: * Return the current indent step.
137: *
138: * <p>Return the current indent step: each start tag will be
139: * indented by this number of spaces times the number of
140: * ancestors that the element has.</p>
141: *
142: * @return The number of spaces in each indentation step,
143: * or 0 or less for no indentation.
144: * @see #setIndentStep(int)
145: *
146: * @deprecated
147: * Only return the length of the indent string.
148: */
149: public int getIndentStep() {
150: return indentStep.length();
151: }
152:
153: /**
154: * Set the current indent step.
155: *
156: * @param indentStep The new indent step (0 or less for no
157: * indentation).
158: * @see #getIndentStep()
159: *
160: * @deprecated
161: * Should use the version that takes string.
162: */
163: public void setIndentStep(int indentStep) {
164: StringBuilder buf = new StringBuilder();
165: for (; indentStep > 0; indentStep--)
166: buf.append(' ');
167: setIndentStep(buf.toString());
168: }
169:
170: public void setIndentStep(String s) {
171: this .indentStep = s;
172: }
173:
174: ////////////////////////////////////////////////////////////////////
175: // Override methods from XMLWriter.
176: ////////////////////////////////////////////////////////////////////
177:
178: /**
179: * Reset the writer so that it can be reused.
180: *
181: * <p>This method is especially useful if the writer failed
182: * with an exception the last time through.</p>
183: *
184: * @see XMLWriter#reset()
185: */
186: public void reset() {
187: depth = 0;
188: state = SEEN_NOTHING;
189: stateStack = new Stack<Object>();
190: super .reset();
191: }
192:
193: protected void writeXmlDecl(String decl) throws IOException {
194: super .writeXmlDecl(decl);
195: write('\n');
196: }
197:
198: /**
199: * Write a start tag.
200: *
201: * <p>Each tag will begin on a new line, and will be
202: * indented by the current indent step times the number
203: * of ancestors that the element has.</p>
204: *
205: * <p>The newline and indentation will be passed on down
206: * the filter chain through regular characters events.</p>
207: *
208: * @param uri The element's Namespace URI.
209: * @param localName The element's local name.
210: * @param qName The element's qualified (prefixed) name.
211: * @param atts The element's attribute list.
212: * @exception org.xml.sax.SAXException If there is an error
213: * writing the start tag, or if a filter further
214: * down the chain raises an exception.
215: * @see XMLWriter#startElement(String, String, String, Attributes)
216: */
217: public void startElement(String uri, String localName,
218: String qName, Attributes atts) throws SAXException {
219: stateStack.push(SEEN_ELEMENT);
220: state = SEEN_NOTHING;
221: if (depth > 0) {
222: super .characters("\n");
223: }
224: doIndent();
225: super .startElement(uri, localName, qName, atts);
226: depth++;
227: }
228:
229: /**
230: * Write an end tag.
231: *
232: * <p>If the element has contained other elements, the tag
233: * will appear indented on a new line; otherwise, it will
234: * appear immediately following whatever came before.</p>
235: *
236: * <p>The newline and indentation will be passed on down
237: * the filter chain through regular characters events.</p>
238: *
239: * @param uri The element's Namespace URI.
240: * @param localName The element's local name.
241: * @param qName The element's qualified (prefixed) name.
242: * @exception org.xml.sax.SAXException If there is an error
243: * writing the end tag, or if a filter further
244: * down the chain raises an exception.
245: * @see XMLWriter#endElement(String, String, String)
246: */
247: public void endElement(String uri, String localName, String qName)
248: throws SAXException {
249: depth--;
250: if (state == SEEN_ELEMENT) {
251: super .characters("\n");
252: doIndent();
253: }
254: super .endElement(uri, localName, qName);
255: state = stateStack.pop();
256: }
257:
258: public void endDocument() throws SAXException {
259: try {
260: write('\n');
261: } catch (IOException e) {
262: throw new SAXException(e);
263: }
264: super .endDocument();
265: }
266:
267: // /**
268: // * Write a empty element tag.
269: // *
270: // * <p>Each tag will appear on a new line, and will be
271: // * indented by the current indent step times the number
272: // * of ancestors that the element has.</p>
273: // *
274: // * <p>The newline and indentation will be passed on down
275: // * the filter chain through regular characters events.</p>
276: // *
277: // * @param uri The element's Namespace URI.
278: // * @param localName The element's local name.
279: // * @param qName The element's qualified (prefixed) name.
280: // * @param atts The element's attribute list.
281: // * @exception org.xml.sax.SAXException If there is an error
282: // * writing the empty tag, or if a filter further
283: // * down the chain raises an exception.
284: // * @see XMLWriter#emptyElement(String, String, String, Attributes)
285: // */
286: // public void emptyElement (String uri, String localName,
287: // String qName, Attributes atts)
288: // throws SAXException
289: // {
290: // state = SEEN_ELEMENT;
291: // if (depth > 0) {
292: // super.characters("\n");
293: // }
294: // doIndent();
295: // super.emptyElement(uri, localName, qName, atts);
296: // }
297:
298: /**
299: * Write a sequence of characters.
300: *
301: * @param ch The characters to write.
302: * @param start The starting position in the array.
303: * @param length The number of characters to use.
304: * @exception org.xml.sax.SAXException If there is an error
305: * writing the characters, or if a filter further
306: * down the chain raises an exception.
307: * @see XMLWriter#characters(char[], int, int)
308: */
309: public void characters(char ch[], int start, int length)
310: throws SAXException {
311: state = SEEN_DATA;
312: super .characters(ch, start, length);
313: }
314:
315: ////////////////////////////////////////////////////////////////////
316: // Internal methods.
317: ////////////////////////////////////////////////////////////////////
318:
319: /**
320: * Print indentation for the current level.
321: *
322: * @exception org.xml.sax.SAXException If there is an error
323: * writing the indentation characters, or if a filter
324: * further down the chain raises an exception.
325: */
326: private void doIndent() throws SAXException {
327: if (depth > 0) {
328: char[] ch = indentStep.toCharArray();
329: for (int i = 0; i < depth; i++)
330: characters(ch, 0, ch.length);
331: }
332: }
333:
334: ////////////////////////////////////////////////////////////////////
335: // Constants.
336: ////////////////////////////////////////////////////////////////////
337:
338: private final static Object SEEN_NOTHING = new Object();
339: private final static Object SEEN_ELEMENT = new Object();
340: private final static Object SEEN_DATA = new Object();
341:
342: ////////////////////////////////////////////////////////////////////
343: // Internal state.
344: ////////////////////////////////////////////////////////////////////
345:
346: private Object state = SEEN_NOTHING;
347: private Stack<Object> stateStack = new Stack<Object>();
348:
349: private String indentStep = "";
350: private int depth = 0;
351:
352: }
353:
354: // end of DataWriter.java
|