KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > sax > DataFormatFilter


1 /*--
2
3  Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
4  All rights reserved.
5  
6  Redistribution and use in source and binary forms, with or without
7  modification, are permitted provided that the following conditions
8  are met:
9  
10  1. Redistributions of source code must retain the above copyright
11     notice, this list of conditions, and the following disclaimer.
12  
13  2. Redistributions in binary form must reproduce the above copyright
14     notice, this list of conditions, and the disclaimer that follows
15     these conditions in the documentation and/or other materials
16     provided with the distribution.
17
18  3. The name "JDOM" must not be used to endorse or promote products
19     derived from this software without prior written permission. For
20     written permission, please contact license@jdom.org.
21  
22  4. Products derived from this software may not be called "JDOM", nor
23     may "JDOM" appear in their name, without prior written permission
24     from the JDOM Project Management (pm@jdom.org).
25  
26  In addition, we request (but do not require) that you include in the
27  end-user documentation provided with the redistribution and/or in the
28  software itself an acknowledgement equivalent to the following:
29      "This product includes software developed by the
30       JDOM Project (http://www.jdom.org/)."
31  Alternatively, the acknowledgment may be graphical using the logos
32  available at http://www.jdom.org/images/logos.
33
34  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
35  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
36  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37  DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
38  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
39  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
40  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
41  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
42  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
43  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
44  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45  SUCH DAMAGE.
46
47  This software consists of voluntary contributions made by many
48  individuals on behalf of the JDOM Project and was originally
49  created by Brett McLaughlin <brett@jdom.org> and
50  Jason Hunter <jhunter@jdom.org>. For more information on the
51  JDOM Project, please see <http://www.jdom.org/>.
52  
53  */

54 package sax;
55
56 import java.util.Stack JavaDoc;
57
58 import org.xml.sax.Attributes JavaDoc;
59 import org.xml.sax.SAXException JavaDoc;
60 import org.xml.sax.XMLReader JavaDoc;
61
62
63 /**
64  * Filter for data- or field-oriented XML.
65  *
66  * <i>Code and comments adapted from DataWriter-0.2, written
67  * by David Megginson and released into the public domain,
68  * without warranty.</i>
69  *
70  * <p>This filter adds indentation and newlines to field-oriented
71  * XML without mixed content. All added indentation and newlines
72  * will be passed on down the filter chain.</p>
73  *
74  * <p>In general, all whitespace in an XML document is potentially
75  * significant. There is, however, a large class of XML documents
76  * where information is strictly fielded: each element contains either
77  * character data or other elements, but not both. For this special
78  * case, it is possible for a filter to provide automatic indentation
79  * and newlines. Note that this class will likely not yield appropriate
80  * results for document-oriented XML like XHTML pages, which mix character
81  * data and elements together.</p>
82  *
83  * <p>This filter will automatically place each start tag on a new line,
84  * optionally indented if an indent step is provided (by default, there
85  * is no indentation). If an element contains other elements, the end
86  * tag will also appear on a new line with leading indentation. Consider,
87  * for example, the following code:</p>
88  *
89  * <pre>
90  * DataFormatFilter df = new DataFormatFilter();
91  * df.setContentHandler(new XMLWriter());
92  *
93  * df.setIndentStep(2);
94  * df.startDocument();
95  * df.startElement("Person");
96  * df.dataElement("name", "Jane Smith");
97  * df.dataElement("date-of-birth", "1965-05-23");
98  * df.dataElement("citizenship", "US");
99  * df.endElement("Person");
100  * df.endDocument();
101  * </pre>
102  *
103  * <p>This code will produce the following document:</p>
104  *
105  * <pre>
106  * &lt;?xml version="1.0"?>
107  *
108  * &lt;Person>
109  * &lt;name>Jane Smith&lt;/name>
110  * &lt;date-of-birth>1965-05-23&lt;/date-of-birth>
111  * &lt;citizenship>US&lt;/citizenship>
112  * &lt;/Person>
113  * </pre>
114  *
115  * @see DataUnformatFilter
116  */

117 public class DataFormatFilter extends XMLFilterBase
118 {
119     
120     
121     
122     ////////////////////////////////////////////////////////////////////
123
// Constructors.
124
////////////////////////////////////////////////////////////////////
125

126     
127     /**
128      * Create a new filter.
129      */

130     public DataFormatFilter()
131     {
132     }
133
134
135     /**
136      * Create a new filter.
137      *
138      * <p>Use the XMLReader provided as the source of events.</p>
139      *
140      * @param xmlreader The parent in the filter chain.
141      */

142     public DataFormatFilter(XMLReader JavaDoc xmlreader)
143     {
144         super(xmlreader);
145     }
146
147
148     ////////////////////////////////////////////////////////////////////
149
// Accessors and setters.
150
////////////////////////////////////////////////////////////////////
151

152
153     /**
154      * Return the current indent step.
155      *
156      * <p>Return the current indent step: each start tag will be
157      * indented by this number of spaces times the number of
158      * ancestors that the element has.</p>
159      *
160      * @return The number of spaces in each indentation step,
161      * or 0 or less for no indentation.
162      * @see #setIndentStep
163      */

164     public int getIndentStep ()
165     {
166         return indentStep;
167     }
168
169
170     /**
171      * Set the current indent step.
172      *
173      * @param indentStep The new indent step (0 or less for no
174      * indentation).
175      * @see #getIndentStep
176      */

177     public void setIndentStep (int indentStep)
178     {
179         this.indentStep = indentStep;
180     }
181     
182     
183     
184     ////////////////////////////////////////////////////////////////////
185
// Public methods.
186
////////////////////////////////////////////////////////////////////
187

188
189     /**
190      * Reset the filter so that it can be reused.
191      *
192      * <p>This method is especially useful if the filter failed
193      * with an exception the last time through.</p>
194      */

195     public void reset ()
196     {
197         state = SEEN_NOTHING;
198         stateStack = new Stack JavaDoc();
199     }
200
201
202
203     ////////////////////////////////////////////////////////////////////
204
// Methods from org.xml.sax.ContentHandler.
205
////////////////////////////////////////////////////////////////////
206

207     
208     /**
209      * Filter a start document event.
210      *
211      * <p>Reset state and pass the event on for further processing.</p>
212      *
213      * @exception org.xml.sax.SAXException If a filter
214      * further down the chain raises an exception.
215      * @see org.xml.sax.ContentHandler#startDocument
216      */

217     public void startDocument ()
218     throws SAXException JavaDoc
219     {
220         reset();
221         super.startDocument();
222     }
223
224
225     /**
226      * Add newline and indentation prior to start tag.
227      *
228      * <p>Each tag will begin on a new line, and will be
229      * indented by the current indent step times the number
230      * of ancestors that the element has.</p>
231      *
232      * <p>The newline and indentation will be passed on down
233      * the filter chain through regular characters events.</p>
234      *
235      * @param uri The element's Namespace URI.
236      * @param localName The element's local name.
237      * @param qName The element's qualified (prefixed) name.
238      * @param atts The element's attribute list.
239      * @exception org.xml.sax.SAXException If a filter
240      * further down the chain raises an exception.
241      * @see org.xml.sax.ContentHandler#startElement
242      */

243     public void startElement (String JavaDoc uri, String JavaDoc localName,
244                               String JavaDoc qName, Attributes JavaDoc atts)
245     throws SAXException JavaDoc
246     {
247         if (!stateStack.empty()) {
248             doNewline();
249             doIndent();
250         }
251         stateStack.push(SEEN_ELEMENT);
252         state = SEEN_NOTHING;
253         super.startElement(uri, localName, qName, atts);
254     }
255
256
257     /**
258      * Add newline and indentation prior to end tag.
259      *
260      * <p>If the element has contained other elements, the tag
261      * will appear indented on a new line; otherwise, it will
262      * appear immediately following whatever came before.</p>
263      *
264      * <p>The newline and indentation will be passed on down
265      * the filter chain through regular characters events.</p>
266      *
267      * @param uri The element's Namespace URI.
268      * @param localName The element's local name.
269      * @param qName The element's qualified (prefixed) name.
270      * @exception org.xml.sax.SAXException If a filter
271      * further down the chain raises an exception.
272      * @see org.xml.sax.ContentHandler#endElement
273      */

274     public void endElement (String JavaDoc uri, String JavaDoc localName, String JavaDoc qName)
275     throws SAXException JavaDoc
276     {
277         boolean seenElement = (state == SEEN_ELEMENT);
278         state = stateStack.pop();
279         if (seenElement) {
280             doNewline();
281             doIndent();
282         }
283         super.endElement(uri, localName, qName);
284     }
285
286
287     /**
288      * Filter a character data event.
289      *
290      * @param ch The characters to write.
291      * @param start The starting position in the array.
292      * @param length The number of characters to use.
293      * @exception org.xml.sax.SAXException If a filter
294      * further down the chain raises an exception.
295      * @see org.xml.sax.ContentHandler#characters
296      */

297     public void characters (char ch[], int start, int length)
298     throws SAXException JavaDoc
299     {
300         state = SEEN_DATA;
301         super.characters(ch, start, length);
302     }
303     
304
305
306     ////////////////////////////////////////////////////////////////////
307
// Internal methods.
308
////////////////////////////////////////////////////////////////////
309

310
311     /**
312      * Add newline.
313      *
314      * @exception org.xml.sax.SAXException If a filter
315      * further down the chain raises an exception.
316      */

317     private void doNewline ()
318     throws SAXException JavaDoc
319     {
320         super.characters(NEWLINE, 0, NEWLINE.length);
321     }
322
323
324     /**
325      * Add indentation for the current level.
326      *
327      * @exception org.xml.sax.SAXException If a filter
328      * further down the chain raises an exception.
329      */

330     private void doIndent ()
331     throws SAXException JavaDoc
332     {
333         int n = indentStep * stateStack.size();
334         if (n > 0) {
335             char ch[] = new char[n];
336             for (int i = 0; i < n; i++) {
337                 ch[i] = INDENT_CHAR;
338             }
339             super.characters(ch, 0, n);
340         }
341     }
342
343
344
345
346     ////////////////////////////////////////////////////////////////////
347
// Constants.
348
////////////////////////////////////////////////////////////////////
349

350     private static final Object JavaDoc SEEN_NOTHING = new Object JavaDoc();
351     private static final Object JavaDoc SEEN_ELEMENT = new Object JavaDoc();
352     private static final Object JavaDoc SEEN_DATA = new Object JavaDoc();
353
354     private static final char[] NEWLINE = new char[] {'\n'};
355     private static final char INDENT_CHAR = ' ';
356     
357     
358     ////////////////////////////////////////////////////////////////////
359
// Internal state.
360
////////////////////////////////////////////////////////////////////
361

362     private Object JavaDoc state = SEEN_NOTHING;
363     private Stack JavaDoc stateStack = new Stack JavaDoc();
364
365     private int indentStep = 0;
366
367 }
368
369 // end of DataFormatFilter.java
370
Popular Tags