|
1 /* |
|
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 //@@3RD PARTY CODE@@ |
|
27 |
|
28 // DataWriter.java - XML writer for data-oriented files. |
|
29 |
|
30 package com.sun.xml.internal.bind.marshaller; |
|
31 |
|
32 import java.io.IOException; |
|
33 import java.io.Writer; |
|
34 import java.util.Stack; |
|
35 |
|
36 import org.xml.sax.Attributes; |
|
37 import org.xml.sax.SAXException; |
|
38 |
|
39 |
|
40 /** |
|
41 * Write data- or field-oriented XML. |
|
42 * |
|
43 * <p>This filter pretty-prints field-oriented XML without mixed content. |
|
44 * all added indentation and newlines will be passed on down |
|
45 * the filter chain (if any).</p> |
|
46 * |
|
47 * <p>In general, all whitespace in an XML document is potentially |
|
48 * significant, so a general-purpose XML writing tool like the |
|
49 * {@link XMLWriter} class cannot |
|
50 * add newlines or indentation.</p> |
|
51 * |
|
52 * <p>There is, however, a large class of XML documents where information |
|
53 * is strictly fielded: each element contains either character data |
|
54 * or other elements, but not both. For this special case, it is possible |
|
55 * for a writing tool to provide automatic indentation and newlines |
|
56 * without requiring extra work from the user. Note that this class |
|
57 * will likely not yield appropriate results for document-oriented |
|
58 * XML like XHTML pages, which mix character data and elements together.</p> |
|
59 * |
|
60 * <p>This writer will automatically place each start tag on a new line, |
|
61 * optionally indented if an indent step is provided (by default, there |
|
62 * is no indentation). If an element contains other elements, the end |
|
63 * tag will also appear on a new line with leading indentation. Consider, |
|
64 * for example, the following code:</p> |
|
65 * |
|
66 * <pre> |
|
67 * DataWriter w = new DataWriter(); |
|
68 * |
|
69 * w.setIndentStep(2); |
|
70 * w.startDocument(); |
|
71 * w.startElement("Person"); |
|
72 * w.dataElement("name", "Jane Smith"); |
|
73 * w.dataElement("date-of-birth", "1965-05-23"); |
|
74 * w.dataElement("citizenship", "US"); |
|
75 * w.endElement("Person"); |
|
76 * w.endDocument(); |
|
77 * </pre> |
|
78 * |
|
79 * <p>This code will produce the following document:</p> |
|
80 * |
|
81 * <pre> |
|
82 * <?xml version="1.0" standalone="yes"?> |
|
83 * |
|
84 * <Person> |
|
85 * <name>Jane Smith</name> |
|
86 * <date-of-birth>1965-05-23</date-of-birth> |
|
87 * <citizenship>US</citizenship> |
|
88 * </Person> |
|
89 * </pre> |
|
90 * |
|
91 * <p>This class inherits from {@link XMLWriter}, |
|
92 * and provides all of the same support for Namespaces.</p> |
|
93 * |
|
94 * @since 1.0 |
|
95 * @author David Megginson, david@megginson.com |
|
96 * @version 0.2 |
|
97 * @see XMLWriter |
|
98 */ |
|
99 public class DataWriter extends XMLWriter |
|
100 { |
|
101 |
|
102 |
|
103 |
|
104 //////////////////////////////////////////////////////////////////// |
|
105 // Constructors. |
|
106 //////////////////////////////////////////////////////////////////// |
|
107 |
|
108 |
|
109 /** |
|
110 * Create a new data writer for the specified output. |
|
111 * |
|
112 * @param writer The character stream where the XML document |
|
113 * will be written. |
|
114 * @param encoding |
|
115 * If non-null string is specified, it is written as a part |
|
116 * of the XML declaration. |
|
117 */ |
|
118 public DataWriter ( Writer writer, String encoding, CharacterEscapeHandler _escapeHandler ) |
|
119 { |
|
120 super(writer,encoding,_escapeHandler); |
|
121 } |
|
122 |
|
123 |
|
124 public DataWriter (Writer writer, String encoding ) { |
|
125 this( writer, encoding, DumbEscapeHandler.theInstance ); |
|
126 } |
|
127 |
|
128 |
|
129 |
|
130 //////////////////////////////////////////////////////////////////// |
|
131 // Accessors and setters. |
|
132 //////////////////////////////////////////////////////////////////// |
|
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 { |
|
151 return indentStep.length(); |
|
152 } |
|
153 |
|
154 |
|
155 /** |
|
156 * Set the current indent step. |
|
157 * |
|
158 * @param indentStep The new indent step (0 or less for no |
|
159 * indentation). |
|
160 * @see #getIndentStep() |
|
161 * |
|
162 * @deprecated |
|
163 * Should use the version that takes string. |
|
164 */ |
|
165 public void setIndentStep (int indentStep) |
|
166 { |
|
167 StringBuilder buf = new StringBuilder(); |
|
168 for( ; indentStep>0; indentStep-- ) |
|
169 buf.append(' '); |
|
170 setIndentStep(buf.toString()); |
|
171 } |
|
172 |
|
173 public void setIndentStep(String s) { |
|
174 this.indentStep = s; |
|
175 } |
|
176 |
|
177 |
|
178 |
|
179 //////////////////////////////////////////////////////////////////// |
|
180 // Override methods from XMLWriter. |
|
181 //////////////////////////////////////////////////////////////////// |
|
182 |
|
183 |
|
184 /** |
|
185 * Reset the writer so that it can be reused. |
|
186 * |
|
187 * <p>This method is especially useful if the writer failed |
|
188 * with an exception the last time through.</p> |
|
189 * |
|
190 * @see XMLWriter#reset() |
|
191 */ |
|
192 public void reset () |
|
193 { |
|
194 depth = 0; |
|
195 state = SEEN_NOTHING; |
|
196 stateStack = new Stack<Object>(); |
|
197 super.reset(); |
|
198 } |
|
199 |
|
200 protected void writeXmlDecl(String decl) throws IOException { |
|
201 super.writeXmlDecl(decl); |
|
202 write('\n'); |
|
203 } |
|
204 |
|
205 |
|
206 /** |
|
207 * Write a start tag. |
|
208 * |
|
209 * <p>Each tag will begin on a new line, and will be |
|
210 * indented by the current indent step times the number |
|
211 * of ancestors that the element has.</p> |
|
212 * |
|
213 * <p>The newline and indentation will be passed on down |
|
214 * the filter chain through regular characters events.</p> |
|
215 * |
|
216 * @param uri The element's Namespace URI. |
|
217 * @param localName The element's local name. |
|
218 * @param qName The element's qualified (prefixed) name. |
|
219 * @param atts The element's attribute list. |
|
220 * @exception org.xml.sax.SAXException If there is an error |
|
221 * writing the start tag, or if a filter further |
|
222 * down the chain raises an exception. |
|
223 * @see XMLWriter#startElement(String, String, String, Attributes) |
|
224 */ |
|
225 public void startElement (String uri, String localName, |
|
226 String qName, Attributes atts) |
|
227 throws SAXException |
|
228 { |
|
229 stateStack.push(SEEN_ELEMENT); |
|
230 state = SEEN_NOTHING; |
|
231 if (depth > 0) { |
|
232 super.characters("\n"); |
|
233 } |
|
234 doIndent(); |
|
235 super.startElement(uri, localName, qName, atts); |
|
236 depth++; |
|
237 } |
|
238 |
|
239 |
|
240 /** |
|
241 * Write an end tag. |
|
242 * |
|
243 * <p>If the element has contained other elements, the tag |
|
244 * will appear indented on a new line; otherwise, it will |
|
245 * appear immediately following whatever came before.</p> |
|
246 * |
|
247 * <p>The newline and indentation will be passed on down |
|
248 * the filter chain through regular characters events.</p> |
|
249 * |
|
250 * @param uri The element's Namespace URI. |
|
251 * @param localName The element's local name. |
|
252 * @param qName The element's qualified (prefixed) name. |
|
253 * @exception org.xml.sax.SAXException If there is an error |
|
254 * writing the end tag, or if a filter further |
|
255 * down the chain raises an exception. |
|
256 * @see XMLWriter#endElement(String, String, String) |
|
257 */ |
|
258 public void endElement (String uri, String localName, String qName) |
|
259 throws SAXException |
|
260 { |
|
261 depth--; |
|
262 if (state == SEEN_ELEMENT) { |
|
263 super.characters("\n"); |
|
264 doIndent(); |
|
265 } |
|
266 super.endElement(uri, localName, qName); |
|
267 state = stateStack.pop(); |
|
268 } |
|
269 |
|
270 public void endDocument() throws SAXException { |
|
271 try { |
|
272 write('\n'); |
|
273 } catch( IOException e ) { |
|
274 throw new SAXException(e); |
|
275 } |
|
276 super.endDocument(); |
|
277 } |
|
278 |
|
279 // /** |
|
280 // * Write a empty element tag. |
|
281 // * |
|
282 // * <p>Each tag will appear on a new line, and will be |
|
283 // * indented by the current indent step times the number |
|
284 // * of ancestors that the element has.</p> |
|
285 // * |
|
286 // * <p>The newline and indentation will be passed on down |
|
287 // * the filter chain through regular characters events.</p> |
|
288 // * |
|
289 // * @param uri The element's Namespace URI. |
|
290 // * @param localName The element's local name. |
|
291 // * @param qName The element's qualified (prefixed) name. |
|
292 // * @param atts The element's attribute list. |
|
293 // * @exception org.xml.sax.SAXException If there is an error |
|
294 // * writing the empty tag, or if a filter further |
|
295 // * down the chain raises an exception. |
|
296 // * @see XMLWriter#emptyElement(String, String, String, Attributes) |
|
297 // */ |
|
298 // public void emptyElement (String uri, String localName, |
|
299 // String qName, Attributes atts) |
|
300 // throws SAXException |
|
301 // { |
|
302 // state = SEEN_ELEMENT; |
|
303 // if (depth > 0) { |
|
304 // super.characters("\n"); |
|
305 // } |
|
306 // doIndent(); |
|
307 // super.emptyElement(uri, localName, qName, atts); |
|
308 // } |
|
309 |
|
310 |
|
311 /** |
|
312 * Write a sequence of characters. |
|
313 * |
|
314 * @param ch The characters to write. |
|
315 * @param start The starting position in the array. |
|
316 * @param length The number of characters to use. |
|
317 * @exception org.xml.sax.SAXException If there is an error |
|
318 * writing the characters, or if a filter further |
|
319 * down the chain raises an exception. |
|
320 * @see XMLWriter#characters(char[], int, int) |
|
321 */ |
|
322 public void characters (char ch[], int start, int length) |
|
323 throws SAXException |
|
324 { |
|
325 state = SEEN_DATA; |
|
326 super.characters(ch, start, length); |
|
327 } |
|
328 |
|
329 |
|
330 |
|
331 //////////////////////////////////////////////////////////////////// |
|
332 // Internal methods. |
|
333 //////////////////////////////////////////////////////////////////// |
|
334 |
|
335 |
|
336 /** |
|
337 * Print indentation for the current level. |
|
338 * |
|
339 * @exception org.xml.sax.SAXException If there is an error |
|
340 * writing the indentation characters, or if a filter |
|
341 * further down the chain raises an exception. |
|
342 */ |
|
343 private void doIndent () |
|
344 throws SAXException |
|
345 { |
|
346 if (depth > 0) { |
|
347 char[] ch = indentStep.toCharArray(); |
|
348 for( int i=0; i<depth; i++ ) |
|
349 characters(ch, 0, ch.length); |
|
350 } |
|
351 } |
|
352 |
|
353 |
|
354 |
|
355 //////////////////////////////////////////////////////////////////// |
|
356 // Constants. |
|
357 //////////////////////////////////////////////////////////////////// |
|
358 |
|
359 private final static Object SEEN_NOTHING = new Object(); |
|
360 private final static Object SEEN_ELEMENT = new Object(); |
|
361 private final static Object SEEN_DATA = new Object(); |
|
362 |
|
363 |
|
364 |
|
365 //////////////////////////////////////////////////////////////////// |
|
366 // Internal state. |
|
367 //////////////////////////////////////////////////////////////////// |
|
368 |
|
369 private Object state = SEEN_NOTHING; |
|
370 private Stack<Object> stateStack = new Stack<Object>(); |
|
371 |
|
372 private String indentStep = ""; |
|
373 private int depth = 0; |
|
374 |
|
375 } |
|
376 |
|
377 // end of DataWriter.java |