1   // XMLWriter.java - serialize an XML document.
2   // Written by David Megginson, david@megginson.com
3   // NO WARRANTY! This class is in the public domain.
4   
5   // $Id:XMLWriter.java 378 2007-01-24 01:18:35Z mrohrmoser $
6   
7   package com.megginson.sax;
8   
9   import java.io.IOException;
10  import java.io.OutputStreamWriter;
11  import java.io.Writer;
12  import java.util.Enumeration;
13  import java.util.Hashtable;
14  
15  import org.xml.sax.Attributes;
16  import org.xml.sax.SAXException;
17  import org.xml.sax.XMLReader;
18  import org.xml.sax.helpers.AttributesImpl;
19  import org.xml.sax.helpers.NamespaceSupport;
20  import org.xml.sax.helpers.XMLFilterImpl;
21  
22  /**
23   * Filter to write an XML document from a SAX event stream.
24   * 
25   * <p>
26   * This class can be used by itself or as part of a SAX event stream: it takes
27   * as input a series of SAX2 ContentHandler events and uses the information in
28   * those events to write an XML document. Since this class is a filter, it can
29   * also pass the events on down a filter chain for further processing (you can
30   * use the XMLWriter to take a snapshot of the current state at any point in a
31   * filter chain), and it can be used directly as a ContentHandler for a SAX2
32   * XMLReader.
33   * </p>
34   * 
35   * <p>
36   * The client creates a document by invoking the methods for standard SAX2
37   * events, always beginning with the {@link #startDocument startDocument} method
38   * and ending with the {@link #endDocument endDocument} method. There are
39   * convenience methods provided so that clients to not have to create empty
40   * attribute lists or provide empty strings as parameters; for example, the
41   * method invocation
42   * </p>
43   * 
44   * <pre>
45   * w.startElement(&quot;foo&quot;);
46   * </pre>
47   * 
48   * <p>
49   * is equivalent to the regular SAX2 ContentHandler method
50   * </p>
51   * 
52   * <pre>
53   * w.startElement(&quot;&quot;, &quot;foo&quot;, &quot;&quot;, new AttributesImpl());
54   * </pre>
55   * 
56   * <p>
57   * Except that it is more efficient because it does not allocate a new empty
58   * attribute list each time. The following code will send a simple XML document
59   * to standard output:
60   * </p>
61   * 
62   * <pre>
63   * XMLWriter w = new XMLWriter();
64   * 
65   * w.startDocument();
66   * w.startElement(&quot;greeting&quot;);
67   * w.characters(&quot;Hello, world!&quot;);
68   * w.endElement(&quot;greeting&quot;);
69   * w.endDocument();
70   * </pre>
71   * 
72   * <p>
73   * The resulting document will look like this:
74   * </p>
75   * 
76   * <pre>
77   *                 &lt;?xml version=&quot;1.0&quot; standalone=&quot;yes&quot;?&gt;
78   *                
79   *                 &lt;greeting&gt;Hello, world!&lt;/greeting&gt;
80   * </pre>
81   * 
82   * <p>
83   * In fact, there is an even simpler convenience method, <var>dataElement</var>,
84   * designed for writing elements that contain only character data, so the code
85   * to generate the document could be shortened to
86   * </p>
87   * 
88   * <pre>
89   * XMLWriter w = new XMLWriter();
90   * 
91   * w.startDocument();
92   * w.dataElement(&quot;greeting&quot;, &quot;Hello, world!&quot;);
93   * w.endDocument();
94   * </pre>
95   * 
96   * <h2>Whitespace</h2>
97   * 
98   * <p>
99   * According to the XML Recommendation, <em>all</em> whitespace in an XML
100  * document is potentially significant to an application, so this class never
101  * adds newlines or indentation. If you insert three elements in a row, as in
102  * </p>
103  * 
104  * <pre>
105  * w.dataElement(&quot;item&quot;, &quot;1&quot;);
106  * w.dataElement(&quot;item&quot;, &quot;2&quot;);
107  * w.dataElement(&quot;item&quot;, &quot;3&quot;);
108  * </pre>
109  * 
110  * <p>
111  * you will end up with
112  * </p>
113  * 
114  * <pre>
115  *                 &lt;item&gt;1&lt;/item&gt;&lt;item&gt;3&lt;/item&gt;&lt;item&gt;3&lt;/item&gt;
116  * </pre>
117  * 
118  * <p>
119  * You need to invoke one of the <var>characters</var> methods explicitly to
120  * add newlines or indentation. Alternatively, you can use
121  * {@link com.megginson.sax.DataWriter DataWriter}, which is derived from this
122  * class -- it is optimized for writing purely data-oriented (or field-oriented)
123  * XML, and does automatic linebreaks and indentation (but does not support
124  * mixed content properly).
125  * </p>
126  * 
127  * 
128  * <h2>Namespace Support</h2>
129  * 
130  * <p>
131  * The writer contains extensive support for XML Namespaces, so that a client
132  * application does not have to keep track of prefixes and supply <var>xmlns</var>
133  * attributes. By default, the XML writer will generate Namespace declarations
134  * in the form _NS1, _NS2, etc., wherever they are needed, as in the following
135  * example:
136  * </p>
137  * 
138  * <pre>
139  * w.startDocument();
140  * w.emptyElement(&quot;http://www.foo.com/ns/&quot;, &quot;foo&quot;);
141  * w.endDocument();
142  * </pre>
143  * 
144  * <p>
145  * The resulting document will look like this:
146  * </p>
147  * 
148  * <pre>
149  *                 &lt;?xml version=&quot;1.0&quot; standalone=&quot;yes&quot;?&gt;
150  *                
151  *                 &lt;_NS1:foo xmlns:_NS1=&quot;http://www.foo.com/ns/&quot;/&gt;
152  * </pre>
153  * 
154  * <p>
155  * In many cases, document authors will prefer to choose their own prefixes
156  * rather than using the (ugly) default names. The XML writer allows two methods
157  * for selecting prefixes:
158  * </p>
159  * 
160  * <ol>
161  * <li>the qualified name</li>
162  * <li>the {@link #setPrefix setPrefix} method.</li>
163  * </ol>
164  * 
165  * <p>
166  * Whenever the XML writer finds a new Namespace URI, it checks to see if a
167  * qualified (prefixed) name is also available; if so it attempts to use the
168  * name's prefix (as long as the prefix is not already in use for another
169  * Namespace URI).
170  * </p>
171  * 
172  * <p>
173  * Before writing a document, the client can also pre-map a prefix to a
174  * Namespace URI with the setPrefix method:
175  * </p>
176  * 
177  * <pre>
178  * w.setPrefix(&quot;http://www.foo.com/ns/&quot;, &quot;foo&quot;);
179  * w.startDocument();
180  * w.emptyElement(&quot;http://www.foo.com/ns/&quot;, &quot;foo&quot;);
181  * w.endDocument();
182  * </pre>
183  * 
184  * <p>
185  * The resulting document will look like this:
186  * </p>
187  * 
188  * <pre>
189  *                 &lt;?xml version=&quot;1.0&quot; standalone=&quot;yes&quot;?&gt;
190  *                
191  *                 &lt;foo:foo xmlns:foo=&quot;http://www.foo.com/ns/&quot;/&gt;
192  * </pre>
193  * 
194  * <p>
195  * The default Namespace simply uses an empty string as the prefix:
196  * </p>
197  * 
198  * <pre>
199  * w.setPrefix(&quot;http://www.foo.com/ns/&quot;, &quot;&quot;);
200  * w.startDocument();
201  * w.emptyElement(&quot;http://www.foo.com/ns/&quot;, &quot;foo&quot;);
202  * w.endDocument();
203  * </pre>
204  * 
205  * <p>
206  * The resulting document will look like this:
207  * </p>
208  * 
209  * <pre>
210  *                 &lt;?xml version=&quot;1.0&quot; standalone=&quot;yes&quot;?&gt;
211  *                
212  *                 &lt;foo xmlns=&quot;http://www.foo.com/ns/&quot;/&gt;
213  * </pre>
214  * 
215  * <p>
216  * By default, the XML writer will not declare a Namespace until it is actually
217  * used. Sometimes, this approach will create a large number of Namespace
218  * declarations, as in the following example:
219  * </p>
220  * 
221  * <pre>
222  *                 &lt;xml version=&quot;1.0&quot; standalone=&quot;yes&quot;?&gt;
223  *                
224  *                 &lt;rdf:RDF xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
225  *                  &lt;rdf:Description about=&quot;http://www.foo.com/ids/books/12345&quot;&gt;
226  *                   &lt;dc:title xmlns:dc=&quot;http://www.purl.org/dc/&quot;&gt;A Dark Night&lt;/dc:title&gt;
227  *                   &lt;dc:creator xmlns:dc=&quot;http://www.purl.org/dc/&quot;&gt;Jane Smith&lt;/dc:title&gt;
228  *                   &lt;dc:date xmlns:dc=&quot;http://www.purl.org/dc/&quot;&gt;2000-09-09&lt;/dc:title&gt;
229  *                  &lt;/rdf:Description&gt;
230  *                 &lt;/rdf:RDF&gt;
231  * </pre>
232  * 
233  * <p>
234  * The "rdf" prefix is declared only once, because the RDF Namespace is used by
235  * the root element and can be inherited by all of its descendants; the "dc"
236  * prefix, on the other hand, is declared three times, because no higher element
237  * uses the Namespace. To solve this problem, you can instruct the XML writer to
238  * predeclare Namespaces on the root element even if they are not used there:
239  * </p>
240  * 
241  * <pre>
242  * w.forceNSDecl(&quot;http://www.purl.org/dc/&quot;);
243  * </pre>
244  * 
245  * <p>
246  * Now, the "dc" prefix will be declared on the root element even though it's
247  * not needed there, and can be inherited by its descendants:
248  * </p>
249  * 
250  * <pre>
251  *                 &lt;xml version=&quot;1.0&quot; standalone=&quot;yes&quot;?&gt;
252  *                
253  *                 &lt;rdf:RDF xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;
254  *                             xmlns:dc=&quot;http://www.purl.org/dc/&quot;&gt;
255  *                  &lt;rdf:Description about=&quot;http://www.foo.com/ids/books/12345&quot;&gt;
256  *                   &lt;dc:title&gt;A Dark Night&lt;/dc:title&gt;
257  *                   &lt;dc:creator&gt;Jane Smith&lt;/dc:title&gt;
258  *                   &lt;dc:date&gt;2000-09-09&lt;/dc:title&gt;
259  *                  &lt;/rdf:Description&gt;
260  *                 &lt;/rdf:RDF&gt;
261  * </pre>
262  * 
263  * <p>
264  * This approach is also useful for declaring Namespace prefixes that be used by
265  * qualified names appearing in attribute values or character data.
266  * </p>
267  * 
268  * @author David Megginson, david@megginson.com
269  * @version 0.2
270  * @see org.xml.sax.XMLFilter
271  * @see org.xml.sax.ContentHandler
272  */
273 class XMLWriter extends XMLFilterImpl {
274 
275 	// //////////////////////////////////////////////////////////////////
276 	// Constructors.
277 	// //////////////////////////////////////////////////////////////////
278 
279 	private Hashtable doneDeclTable;
280 
281 	private int elementLevel = 0;
282 
283 	private final Attributes EMPTY_ATTS = new AttributesImpl();
284 
285 	private Hashtable forcedDeclTable;
286 
287 	private NamespaceSupport nsSupport;
288 
289 	// //////////////////////////////////////////////////////////////////
290 	// Public methods.
291 	// //////////////////////////////////////////////////////////////////
292 
293 	private Writer output;
294 
295 	private int prefixCounter = 0;
296 
297 	private Hashtable prefixTable;
298 
299 	/**
300 	 * Create a new XML writer.
301 	 * 
302 	 * <p>
303 	 * Write to standard output.
304 	 * </p>
305 	 */
306 	public XMLWriter() {
307 		init(null);
308 	}
309 
310 	/**
311 	 * Create a new XML writer.
312 	 * 
313 	 * <p>
314 	 * Write to the writer provided.
315 	 * </p>
316 	 * 
317 	 * @param writer
318 	 *            The output destination, or null to use standard output.
319 	 */
320 	public XMLWriter(final Writer writer) {
321 		init(writer);
322 	}
323 
324 	/**
325 	 * Create a new XML writer.
326 	 * 
327 	 * <p>
328 	 * Use the specified XML reader as the parent.
329 	 * </p>
330 	 * 
331 	 * @param xmlreader
332 	 *            The parent in the filter chain, or null for no parent.
333 	 */
334 	public XMLWriter(final XMLReader xmlreader) {
335 		super(xmlreader);
336 		init(null);
337 	}
338 
339 	/**
340 	 * Create a new XML writer.
341 	 * 
342 	 * <p>
343 	 * Use the specified XML reader as the parent, and write to the specified
344 	 * writer.
345 	 * </p>
346 	 * 
347 	 * @param xmlreader
348 	 *            The parent in the filter chain, or null for no parent.
349 	 * @param writer
350 	 *            The output destination, or null to use standard output.
351 	 */
352 	public XMLWriter(final XMLReader xmlreader, final Writer writer) {
353 		super(xmlreader);
354 		init(writer);
355 	}
356 
357 	// //////////////////////////////////////////////////////////////////
358 	// Methods from org.xml.sax.ContentHandler.
359 	// //////////////////////////////////////////////////////////////////
360 
361 	/**
362 	 * Write character data.
363 	 * 
364 	 * Pass the event on down the filter chain for further processing.
365 	 * 
366 	 * @param ch
367 	 *            The array of characters to write.
368 	 * @param start
369 	 *            The starting position in the array.
370 	 * @param len
371 	 *            The number of characters to write.
372 	 * @exception org.xml.sax.SAXException
373 	 *                If there is an error writing the characters, or if a
374 	 *                handler further down the filter chain raises an exception.
375 	 * @see org.xml.sax.ContentHandler#characters
376 	 */
377 	@Override
378 	public void characters(final char ch[], final int start, final int len)
379 			throws SAXException {
380 		writeEsc(ch, start, len, false);
381 		super.characters(ch, start, len);
382 	}
383 
384 	/**
385 	 * Write a string of character data, with XML escaping.
386 	 * 
387 	 * <p>
388 	 * This is a convenience method that takes an XML String, converts it to a
389 	 * character array, then invokes {@link #characters(char[], int, int)}.
390 	 * </p>
391 	 * 
392 	 * @param data
393 	 *            The character data.
394 	 * @exception org.xml.sax.SAXException
395 	 *                If there is an error writing the string, or if a handler
396 	 *                further down the filter chain raises an exception.
397 	 * @see #characters(char[], int, int)
398 	 */
399 	public void characters(final String data) throws SAXException {
400 		final char ch[] = data.toCharArray();
401 		this.characters(ch, 0, ch.length);
402 	}
403 
404 	/**
405 	 * Write an element with character data content but no attributes or
406 	 * Namespace URI.
407 	 * 
408 	 * <p>
409 	 * This is a convenience method to write a complete element with character
410 	 * data content, including the start tag and end tag. The method provides an
411 	 * empty string for the Namespace URI, and empty string for the qualified
412 	 * name, and an empty attribute list.
413 	 * </p>
414 	 * 
415 	 * <p>
416 	 * This method invokes
417 	 * {@link #startElement(String, String, String, Attributes)}, followed by
418 	 * {@link #characters(String)}, followed by
419 	 * {@link #endElement(String, String, String)}.
420 	 * </p>
421 	 * 
422 	 * @param localName
423 	 *            The element's local name.
424 	 * @param content
425 	 *            The character data content.
426 	 * @exception org.xml.sax.SAXException
427 	 *                If there is an error writing the empty tag, or if a
428 	 *                handler further down the filter chain raises an exception.
429 	 * @see #startElement(String, String, String, Attributes)
430 	 * @see #characters(String)
431 	 * @see #endElement(String, String, String)
432 	 */
433 	public void dataElement(final String localName, final String content)
434 			throws SAXException {
435 		this.dataElement("", localName, "", EMPTY_ATTS, content);
436 	}
437 
438 	/**
439 	 * Write an element with character data content but no attributes.
440 	 * 
441 	 * <p>
442 	 * This is a convenience method to write a complete element with character
443 	 * data content, including the start tag and end tag. This method provides
444 	 * an empty string for the qname and an empty attribute list.
445 	 * </p>
446 	 * 
447 	 * <p>
448 	 * This method invokes
449 	 * {@link #startElement(String, String, String, Attributes)}, followed by
450 	 * {@link #characters(String)}, followed by
451 	 * {@link #endElement(String, String, String)}.
452 	 * </p>
453 	 * 
454 	 * @param uri
455 	 *            The element's Namespace URI.
456 	 * @param localName
457 	 *            The element's local name.
458 	 * @param content
459 	 *            The character data content.
460 	 * @exception org.xml.sax.SAXException
461 	 *                If there is an error writing the empty tag, or if a
462 	 *                handler further down the filter chain raises an exception.
463 	 * @see #startElement(String, String, String, Attributes)
464 	 * @see #characters(String)
465 	 * @see #endElement(String, String, String)
466 	 */
467 	public void dataElement(final String uri, final String localName,
468 			final String content) throws SAXException {
469 		this.dataElement(uri, localName, "", EMPTY_ATTS, content);
470 	}
471 
472 	/**
473 	 * Write an element with character data content.
474 	 * 
475 	 * <p>
476 	 * This is a convenience method to write a complete element with character
477 	 * data content, including the start tag and end tag.
478 	 * </p>
479 	 * 
480 	 * <p>
481 	 * This method invokes
482 	 * {@link #startElement(String, String, String, Attributes)}, followed by
483 	 * {@link #characters(String)}, followed by
484 	 * {@link #endElement(String, String, String)}.
485 	 * </p>
486 	 * 
487 	 * @param uri
488 	 *            The element's Namespace URI.
489 	 * @param localName
490 	 *            The element's local name.
491 	 * @param qName
492 	 *            The element's default qualified name.
493 	 * @param atts
494 	 *            The element's attributes.
495 	 * @param content
496 	 *            The character data content.
497 	 * @exception org.xml.sax.SAXException
498 	 *                If there is an error writing the empty tag, or if a
499 	 *                handler further down the filter chain raises an exception.
500 	 * @see #startElement(String, String, String, Attributes)
501 	 * @see #characters(String)
502 	 * @see #endElement(String, String, String)
503 	 */
504 	public void dataElement(final String uri, final String localName,
505 			final String qName, final Attributes atts, final String content)
506 			throws SAXException {
507 		this.startElement(uri, localName, qName, atts);
508 		this.characters(content);
509 		this.endElement(uri, localName, qName);
510 	}
511 
512 	/**
513 	 * Determine the prefix for an element or attribute name.
514 	 * 
515 	 * TODO: this method probably needs some cleanup.
516 	 * 
517 	 * @param uri
518 	 *            The Namespace URI.
519 	 * @param qName
520 	 *            The qualified name (optional); this will be used to indicate
521 	 *            the preferred prefix if none is currently bound.
522 	 * @param isElement
523 	 *            true if this is an element name, false if it is an attribute
524 	 *            name (which cannot use the default Namespace).
525 	 * @return ???
526 	 */
527 	private String doPrefix(final String uri, final String qName,
528 			boolean isElement) {
529 		final String defaultNS = nsSupport.getURI("");
530 		if ("".equals(uri)) {
531 			if (isElement && defaultNS != null)
532 				nsSupport.declarePrefix("", "");
533 			return null;
534 		}
535 		String prefix;
536 		if (isElement && defaultNS != null && uri.equals(defaultNS))
537 			prefix = "";
538 		else
539 			prefix = nsSupport.getPrefix(uri);
540 		if (prefix != null)
541 			return prefix;
542 		prefix = (String) doneDeclTable.get(uri);
543 		if (prefix != null
544 				&& ((!isElement || defaultNS != null) && "".equals(prefix) || nsSupport
545 						.getURI(prefix) != null))
546 			prefix = null;
547 		if (prefix == null) {
548 			prefix = (String) prefixTable.get(uri);
549 			if (prefix != null
550 					&& ((!isElement || defaultNS != null) && "".equals(prefix) || nsSupport
551 							.getURI(prefix) != null))
552 				prefix = null;
553 		}
554 		if (prefix == null && qName != null && !"".equals(qName)) {
555 			final int i = qName.indexOf(':');
556 			if (i == -1) {
557 				if (isElement && defaultNS == null)
558 					prefix = "";
559 			} else
560 				prefix = qName.substring(0, i);
561 		}
562 		for (; prefix == null || nsSupport.getURI(prefix) != null; prefix = "__NS"
563 				+ ++prefixCounter)
564 			;
565 		nsSupport.declarePrefix(prefix, uri);
566 		doneDeclTable.put(uri, prefix);
567 		return prefix;
568 	}
569 
570 	/**
571 	 * Add an empty element without a Namespace URI, qname or attributes.
572 	 * 
573 	 * <p>
574 	 * This method will supply an empty string for the qname, and empty string
575 	 * for the Namespace URI, and an empty attribute list. It invokes
576 	 * {@link #emptyElement(String, String, String, Attributes)} directly.
577 	 * </p>
578 	 * 
579 	 * @param localName
580 	 *            The element's local name.
581 	 * @exception org.xml.sax.SAXException
582 	 *                If there is an error writing the empty tag, or if a
583 	 *                handler further down the filter chain raises an exception.
584 	 * @see #emptyElement(String, String, String, Attributes)
585 	 */
586 	public void emptyElement(final String localName) throws SAXException {
587 		this.emptyElement("", localName, "", EMPTY_ATTS);
588 	}
589 
590 	// //////////////////////////////////////////////////////////////////
591 	// Additional markup.
592 	// //////////////////////////////////////////////////////////////////
593 
594 	/**
595 	 * Add an empty element without a qname or attributes.
596 	 * 
597 	 * <p>
598 	 * This method will supply an empty string for the qname and an empty
599 	 * attribute list. It invokes
600 	 * {@link #emptyElement(String, String, String, Attributes)} directly.
601 	 * </p>
602 	 * 
603 	 * @param uri
604 	 *            The element's Namespace URI.
605 	 * @param localName
606 	 *            The element's local name.
607 	 * @exception org.xml.sax.SAXException
608 	 *                If there is an error writing the empty tag, or if a
609 	 *                handler further down the filter chain raises an exception.
610 	 * @see #emptyElement(String, String, String, Attributes)
611 	 */
612 	public void emptyElement(final String uri, final String localName)
613 			throws SAXException {
614 		this.emptyElement(uri, localName, "", EMPTY_ATTS);
615 	}
616 
617 	// //////////////////////////////////////////////////////////////////
618 	// Convenience methods.
619 	// //////////////////////////////////////////////////////////////////
620 
621 	/**
622 	 * Write an empty element.
623 	 * 
624 	 * This method writes an empty element tag rather than a start tag followed
625 	 * by an end tag. Both a {@link #startElement(String)} and an
626 	 * {@link #endElement(String) } event will be passed on down the filter
627 	 * chain.
628 	 * 
629 	 * @param uri
630 	 *            The element's Namespace URI, or the empty string if the
631 	 *            element has no Namespace or if Namespace processing is not
632 	 *            being performed.
633 	 * @param localName
634 	 *            The element's local name (without prefix). This parameter must
635 	 *            be provided.
636 	 * @param qName
637 	 *            The element's qualified name (with prefix), or the empty
638 	 *            string if none is available. This parameter is strictly
639 	 *            advisory: the writer may or may not use the prefix attached.
640 	 * @param atts
641 	 *            The element's attribute list.
642 	 * @exception org.xml.sax.SAXException
643 	 *                If there is an error writing the empty tag, or if a
644 	 *                handler further down the filter chain raises an exception.
645 	 * @see #startElement(String, String, String, Attributes)
646 	 * @see #endElement(String, String, String)
647 	 */
648 	public void emptyElement(final String uri, final String localName,
649 			final String qName, final Attributes atts) throws SAXException {
650 		nsSupport.pushContext();
651 		this.write('<');
652 		writeName(uri, localName, qName, true);
653 		writeAttributes(atts);
654 		if (elementLevel == 1)
655 			forceNSDecls();
656 		writeNSDecls();
657 		this.write("/>");
658 		super.startElement(uri, localName, qName, atts);
659 		super.endElement(uri, localName, qName);
660 	}
661 
662 	/**
663 	 * Write a newline at the end of the document.
664 	 * 
665 	 * Pass the event on down the filter chain for further processing.
666 	 * 
667 	 * @exception org.xml.sax.SAXException
668 	 *                If there is an error writing the newline, or if a handler
669 	 *                further down the filter chain raises an exception.
670 	 * @see org.xml.sax.ContentHandler#endDocument
671 	 */
672 	@Override
673 	public void endDocument() throws SAXException {
674 		this.write('\n');
675 		super.endDocument();
676 		try {
677 			flush();
678 		} catch (final IOException e) {
679 			throw new SAXException(e);
680 		}
681 	}
682 
683 	/**
684 	 * End an element without a Namespace URI or qname.
685 	 * 
686 	 * <p>
687 	 * This method will supply an empty string for the qName and an empty string
688 	 * for the Namespace URI. It invokes
689 	 * {@link #endElement(String, String, String)} directly.
690 	 * </p>
691 	 * 
692 	 * @param localName
693 	 *            The element's local name.
694 	 * @exception org.xml.sax.SAXException
695 	 *                If there is an error writing the end tag, or if a handler
696 	 *                further down the filter chain raises an exception.
697 	 * @see #endElement(String, String, String)
698 	 */
699 	public void endElement(final String localName) throws SAXException {
700 		this.endElement("", localName, "");
701 	}
702 
703 	/**
704 	 * End an element without a qname.
705 	 * 
706 	 * <p>
707 	 * This method will supply an empty string for the qName. It invokes
708 	 * {@link #endElement(String, String, String)} directly.
709 	 * </p>
710 	 * 
711 	 * @param uri
712 	 *            The element's Namespace URI.
713 	 * @param localName
714 	 *            The element's local name.
715 	 * @exception org.xml.sax.SAXException
716 	 *                If there is an error writing the end tag, or if a handler
717 	 *                further down the filter chain raises an exception.
718 	 * @see #endElement(String, String, String)
719 	 */
720 	public void endElement(final String uri, final String localName)
721 			throws SAXException {
722 		this.endElement(uri, localName, "");
723 	}
724 
725 	/**
726 	 * Write an end tag.
727 	 * 
728 	 * Pass the event on down the filter chain for further processing.
729 	 * 
730 	 * @param uri
731 	 *            The Namespace URI, or the empty string if none is available.
732 	 * @param localName
733 	 *            The element's local (unprefixed) name (required).
734 	 * @param qName
735 	 *            The element's qualified (prefixed) name, or the empty string
736 	 *            is none is available. This method will use the qName as a
737 	 *            template for generating a prefix if necessary, but it is not
738 	 *            guaranteed to use the same qName.
739 	 * @exception org.xml.sax.SAXException
740 	 *                If there is an error writing the end tag, or if a handler
741 	 *                further down the filter chain raises an exception.
742 	 * @see org.xml.sax.ContentHandler#endElement
743 	 */
744 	@Override
745 	public void endElement(final String uri, final String localName,
746 			final String qName) throws SAXException {
747 		this.write("</");
748 		writeName(uri, localName, qName, true);
749 		this.write('>');
750 		if (elementLevel == 1)
751 			this.write('\n');
752 		super.endElement(uri, localName, qName);
753 		nsSupport.popContext();
754 		elementLevel--;
755 	}
756 
757 	/**
758 	 * Flush the output.
759 	 * 
760 	 * <p>
761 	 * This method flushes the output stream. It is especially useful when you
762 	 * need to make certain that the entire document has been written to output
763 	 * but do not want to close the output stream.
764 	 * </p>
765 	 * 
766 	 * <p>
767 	 * This method is invoked automatically by the
768 	 * {@link #endDocument endDocument} method after writing a document.
769 	 * </p>
770 	 * 
771 	 * @throws IOException
772 	 * @see #reset
773 	 */
774 	public void flush() throws IOException {
775 		output.flush();
776 	}
777 
778 	/**
779 	 * Force a Namespace to be declared on the root element.
780 	 * 
781 	 * <p>
782 	 * By default, the XMLWriter will declare only the Namespaces needed for an
783 	 * element; as a result, a Namespace may be declared many places in a
784 	 * document if it is not used on the root element.
785 	 * </p>
786 	 * 
787 	 * <p>
788 	 * This method forces a Namespace to be declared on the root element even if
789 	 * it is not used there, and reduces the number of xmlns attributes in the
790 	 * document.
791 	 * </p>
792 	 * 
793 	 * @param uri
794 	 *            The Namespace URI to declare.
795 	 * @see #forceNSDecl(java.lang.String,java.lang.String)
796 	 * @see #setPrefix
797 	 */
798 	public void forceNSDecl(final String uri) {
799 		forcedDeclTable.put(uri, Boolean.TRUE);
800 	}
801 
802 	/**
803 	 * Force a Namespace declaration with a preferred prefix.
804 	 * 
805 	 * <p>
806 	 * This is a convenience method that invokes {@link #setPrefix setPrefix}
807 	 * then {@link #forceNSDecl(java.lang.String) forceNSDecl}.
808 	 * </p>
809 	 * 
810 	 * @param uri
811 	 *            The Namespace URI to declare on the root element.
812 	 * @param prefix
813 	 *            The preferred prefix for the Namespace, or "" for the default
814 	 *            Namespace.
815 	 * @see #setPrefix
816 	 * @see #forceNSDecl(java.lang.String)
817 	 */
818 	public void forceNSDecl(final String uri, final String prefix) {
819 		setPrefix(uri, prefix);
820 		this.forceNSDecl(uri);
821 	}
822 
823 	/**
824 	 * Force all Namespaces to be declared.
825 	 * 
826 	 * This method is used on the root element to ensure that the predeclared
827 	 * Namespaces all appear.
828 	 */
829 	private void forceNSDecls() {
830 		final Enumeration prefixes = forcedDeclTable.keys();
831 		while (prefixes.hasMoreElements()) {
832 			final String prefix = (String) prefixes.nextElement();
833 			doPrefix(prefix, null, true);
834 		}
835 	}
836 
837 	/**
838 	 * Get the current or preferred prefix for a Namespace URI.
839 	 * 
840 	 * @param uri
841 	 *            The Namespace URI.
842 	 * @return The preferred prefix, or "" for the default Namespace.
843 	 * @see #setPrefix
844 	 */
845 	public String getPrefix(final String uri) {
846 		return (String) prefixTable.get(uri);
847 	}
848 
849 	// //////////////////////////////////////////////////////////////////
850 	// Internal methods.
851 	// //////////////////////////////////////////////////////////////////
852 
853 	/**
854 	 * Write ignorable whitespace.
855 	 * 
856 	 * Pass the event on down the filter chain for further processing.
857 	 * 
858 	 * @param ch
859 	 *            The array of characters to write.
860 	 * @param start
861 	 *            The starting position in the array.
862 	 * @param length
863 	 *            The number of characters to write.
864 	 * @exception org.xml.sax.SAXException
865 	 *                If there is an error writing the whitespace, or if a
866 	 *                handler further down the filter chain raises an exception.
867 	 * @see org.xml.sax.ContentHandler#ignorableWhitespace
868 	 */
869 	@Override
870 	public void ignorableWhitespace(final char ch[], final int start,
871 			final int length) throws SAXException {
872 		writeEsc(ch, start, length, false);
873 		super.ignorableWhitespace(ch, start, length);
874 	}
875 
876 	/**
877 	 * Internal initialization method.
878 	 * 
879 	 * <p>
880 	 * All of the public constructors invoke this method.
881 	 * 
882 	 * @param writer
883 	 *            The output destination, or null to use standard output.
884 	 */
885 	private void init(final Writer writer) {
886 		setOutput(writer);
887 		nsSupport = new NamespaceSupport();
888 		prefixTable = new Hashtable();
889 		forcedDeclTable = new Hashtable();
890 		doneDeclTable = new Hashtable();
891 	}
892 
893 	/**
894 	 * Write a processing instruction.
895 	 * 
896 	 * Pass the event on down the filter chain for further processing.
897 	 * 
898 	 * @param target
899 	 *            The PI target.
900 	 * @param data
901 	 *            The PI data.
902 	 * @exception org.xml.sax.SAXException
903 	 *                If there is an error writing the PI, or if a handler
904 	 *                further down the filter chain raises an exception.
905 	 * @see org.xml.sax.ContentHandler#processingInstruction
906 	 */
907 	@Override
908 	public void processingInstruction(final String target, final String data)
909 			throws SAXException {
910 		this.write("<?");
911 		this.write(target);
912 		this.write(' ');
913 		this.write(data);
914 		this.write("?>");
915 		if (elementLevel < 1)
916 			this.write('\n');
917 		super.processingInstruction(target, data);
918 	}
919 
920 	/**
921 	 * Reset the writer.
922 	 * 
923 	 * <p>
924 	 * This method is especially useful if the writer throws an exception before
925 	 * it is finished, and you want to reuse the writer for a new document. It
926 	 * is usually a good idea to invoke {@link #flush flush} before resetting
927 	 * the writer, to make sure that no output is lost.
928 	 * </p>
929 	 * 
930 	 * <p>
931 	 * This method is invoked automatically by the
932 	 * {@link #startDocument startDocument} method before writing a new
933 	 * document.
934 	 * </p>
935 	 * 
936 	 * <p>
937 	 * <strong>Note:</strong> this method will <em>not</em> clear the prefix
938 	 * or URI information in the writer or the selected output writer.
939 	 * </p>
940 	 * 
941 	 * @see #flush
942 	 */
943 	public void reset() {
944 		elementLevel = 0;
945 		prefixCounter = 0;
946 		nsSupport.reset();
947 	}
948 
949 	/**
950 	 * Set a new output destination for the document.
951 	 * 
952 	 * @param writer
953 	 *            The output destination, or null to use standard output.
954 	 * @see #flush
955 	 */
956 	public void setOutput(final Writer writer) {
957 		if (writer == null)
958 			output = new OutputStreamWriter(System.out);
959 		else
960 			output = writer;
961 	}
962 
963 	/**
964 	 * Specify a preferred prefix for a Namespace URI.
965 	 * 
966 	 * <p>
967 	 * Note that this method does not actually force the Namespace to be
968 	 * declared; to do that, use the {@link  #forceNSDecl(java.lang.String)
969 	 * forceNSDecl} method as well.
970 	 * </p>
971 	 * 
972 	 * @param uri
973 	 *            The Namespace URI.
974 	 * @param prefix
975 	 *            The preferred prefix, or "" to select the default Namespace.
976 	 * @see #getPrefix
977 	 * @see #forceNSDecl(java.lang.String)
978 	 * @see #forceNSDecl(java.lang.String,java.lang.String)
979 	 */
980 	public void setPrefix(final String uri, final String prefix) {
981 		prefixTable.put(uri, prefix);
982 	}
983 
984 	/**
985 	 * Write the XML declaration at the beginning of the document.
986 	 * 
987 	 * Pass the event on down the filter chain for further processing.
988 	 * 
989 	 * @exception org.xml.sax.SAXException
990 	 *                If there is an error writing the XML declaration, or if a
991 	 *                handler further down the filter chain raises an exception.
992 	 * @see org.xml.sax.ContentHandler#startDocument
993 	 */
994 	@Override
995 	public void startDocument() throws SAXException {
996 		reset();
997 		this.write("<?xml version=\"1.0\" standalone=\"yes\"?>\n\n");
998 		super.startDocument();
999 	}
1000 
1001 	/**
1002 	 * Start a new element without a qname, attributes or a Namespace URI.
1003 	 * 
1004 	 * <p>
1005 	 * This method will provide an empty string for the Namespace URI, and empty
1006 	 * string for the qualified name, and a default empty attribute list. It
1007 	 * invokes #startElement(String, String, String, Attributes)} directly.
1008 	 * </p>
1009 	 * 
1010 	 * @param localName
1011 	 *            The element's local name.
1012 	 * @exception org.xml.sax.SAXException
1013 	 *                If there is an error writing the start tag, or if a
1014 	 *                handler further down the filter chain raises an exception.
1015 	 * @see #startElement(String, String, String, Attributes)
1016 	 */
1017 	public void startElement(final String localName) throws SAXException {
1018 		this.startElement("", localName, "", EMPTY_ATTS);
1019 	}
1020 
1021 	// //////////////////////////////////////////////////////////////////
1022 	// Constants.
1023 	// //////////////////////////////////////////////////////////////////
1024 
1025 	/**
1026 	 * Start a new element without a qname or attributes.
1027 	 * 
1028 	 * <p>
1029 	 * This method will provide a default empty attribute list and an empty
1030 	 * string for the qualified name. It invokes {@link  #startElement(String,
1031 	 * String, String, Attributes)} directly.
1032 	 * </p>
1033 	 * 
1034 	 * @param uri
1035 	 *            The element's Namespace URI.
1036 	 * @param localName
1037 	 *            The element's local name.
1038 	 * @exception org.xml.sax.SAXException
1039 	 *                If there is an error writing the start tag, or if a
1040 	 *                handler further down the filter chain raises an exception.
1041 	 * @see #startElement(String, String, String, Attributes)
1042 	 */
1043 	public void startElement(final String uri, final String localName)
1044 			throws SAXException {
1045 		this.startElement(uri, localName, "", EMPTY_ATTS);
1046 	}
1047 
1048 	// //////////////////////////////////////////////////////////////////
1049 	// Internal state.
1050 	// //////////////////////////////////////////////////////////////////
1051 
1052 	/**
1053 	 * Write a start tag.
1054 	 * 
1055 	 * Pass the event on down the filter chain for further processing.
1056 	 * 
1057 	 * @param uri
1058 	 *            The Namespace URI, or the empty string if none is available.
1059 	 * @param localName
1060 	 *            The element's local (unprefixed) name (required).
1061 	 * @param qName
1062 	 *            The element's qualified (prefixed) name, or the empty string
1063 	 *            is none is available. This method will use the qName as a
1064 	 *            template for generating a prefix if necessary, but it is not
1065 	 *            guaranteed to use the same qName.
1066 	 * @param atts
1067 	 *            The element's attribute list (must not be null).
1068 	 * @exception org.xml.sax.SAXException
1069 	 *                If there is an error writing the start tag, or if a
1070 	 *                handler further down the filter chain raises an exception.
1071 	 * @see org.xml.sax.ContentHandler#startElement
1072 	 */
1073 	@Override
1074 	public void startElement(final String uri, final String localName,
1075 			final String qName, final Attributes atts) throws SAXException {
1076 		elementLevel++;
1077 		nsSupport.pushContext();
1078 		this.write('<');
1079 		writeName(uri, localName, qName, true);
1080 		writeAttributes(atts);
1081 		if (elementLevel == 1)
1082 			forceNSDecls();
1083 		writeNSDecls();
1084 		this.write('>');
1085 		super.startElement(uri, localName, qName, atts);
1086 	}
1087 
1088 	/**
1089 	 * Write a raw character.
1090 	 * 
1091 	 * @param c
1092 	 *            The character to write.
1093 	 * @exception org.xml.sax.SAXException
1094 	 *                If there is an error writing the character, this method
1095 	 *                will throw an IOException wrapped in a SAXException.
1096 	 */
1097 	private void write(final char c) throws SAXException {
1098 		try {
1099 			output.write(c);
1100 		} catch (final IOException e) {
1101 			throw new SAXException(e);
1102 		}
1103 	}
1104 
1105 	/**
1106 	 * Write a raw string.
1107 	 * 
1108 	 * @param s
1109 	 * @exception org.xml.sax.SAXException
1110 	 *                If there is an error writing the string, this method will
1111 	 *                throw an IOException wrapped in a SAXException
1112 	 */
1113 	private void write(final String s) throws SAXException {
1114 		try {
1115 			output.write(s);
1116 		} catch (final IOException e) {
1117 			throw new SAXException(e);
1118 		}
1119 	}
1120 
1121 	/**
1122 	 * Write out an attribute list, escaping values.
1123 	 * 
1124 	 * The names will have prefixes added to them.
1125 	 * 
1126 	 * @param atts
1127 	 *            The attribute list to write.
1128 	 * @exception SAXException
1129 	 *                If there is an error writing the attribute list, this
1130 	 *                method will throw an IOException wrapped in a
1131 	 *                SAXException.
1132 	 */
1133 	private void writeAttributes(final Attributes atts) throws SAXException {
1134 		final int len = atts.getLength();
1135 		for (int i = 0; i < len; i++) {
1136 			final char ch[] = atts.getValue(i).toCharArray();
1137 			this.write(' ');
1138 			writeName(atts.getURI(i), atts.getLocalName(i), atts.getQName(i),
1139 					false);
1140 			this.write("=\"");
1141 			writeEsc(ch, 0, ch.length, true);
1142 			this.write('"');
1143 		}
1144 	}
1145 
1146 	/**
1147 	 * Write an array of data characters with escaping.
1148 	 * 
1149 	 * @param ch
1150 	 *            The array of characters.
1151 	 * @param start
1152 	 *            The starting position.
1153 	 * @param length
1154 	 *            The number of characters to use.
1155 	 * @param isAttVal
1156 	 *            true if this is an attribute value literal.
1157 	 * @exception SAXException
1158 	 *                If there is an error writing the characters, this method
1159 	 *                will throw an IOException wrapped in a SAXException.
1160 	 */
1161 	private void writeEsc(final char ch[], final int start, final int length,
1162 			final boolean isAttVal) throws SAXException {
1163 		for (int i = start; i < start + length; i++)
1164 			switch (ch[i]) {
1165 			case '&':
1166 				this.write("&amp;");
1167 				break;
1168 			case '<':
1169 				this.write("&lt;");
1170 				break;
1171 			case '>':
1172 				this.write("&gt;");
1173 				break;
1174 			case '\"':
1175 				if (isAttVal)
1176 					this.write("&quot;");
1177 				else
1178 					this.write('\"');
1179 				break;
1180 			default:
1181 				if (ch[i] > '\u007f') {
1182 					this.write("&#");
1183 					this.write(Integer.toString(ch[i]));
1184 					this.write(';');
1185 				} else
1186 					this.write(ch[i]);
1187 			}
1188 	}
1189 
1190 	/**
1191 	 * Write an element or attribute name.
1192 	 * 
1193 	 * @param uri
1194 	 *            The Namespace URI.
1195 	 * @param localName
1196 	 *            The local name.
1197 	 * @param qName
1198 	 *            The prefixed name, if available, or the empty string.
1199 	 * @param isElement
1200 	 *            true if this is an element name, false if it is an attribute
1201 	 *            name.
1202 	 * @exception org.xml.sax.SAXException
1203 	 *                This method will throw an IOException wrapped in a
1204 	 *                SAXException if there is an error writing the name.
1205 	 */
1206 	private void writeName(final String uri, final String localName,
1207 			final String qName, final boolean isElement) throws SAXException {
1208 		final String prefix = doPrefix(uri, qName, isElement);
1209 		if (prefix != null && !"".equals(prefix)) {
1210 			this.write(prefix);
1211 			this.write(':');
1212 		}
1213 		this.write(localName);
1214 	}
1215 
1216 	/**
1217 	 * Write out the list of Namespace declarations.
1218 	 * 
1219 	 * @exception org.xml.sax.SAXException
1220 	 *                This method will throw an IOException wrapped in a
1221 	 *                SAXException if there is an error writing the Namespace
1222 	 *                declarations.
1223 	 */
1224 	private void writeNSDecls() throws SAXException {
1225 		final Enumeration prefixes = nsSupport.getDeclaredPrefixes();
1226 		while (prefixes.hasMoreElements()) {
1227 			final String prefix = (String) prefixes.nextElement();
1228 			String uri = nsSupport.getURI(prefix);
1229 			if (uri == null)
1230 				uri = "";
1231 			final char ch[] = uri.toCharArray();
1232 			this.write(' ');
1233 			if ("".equals(prefix))
1234 				this.write("xmlns=\"");
1235 			else {
1236 				this.write("xmlns:");
1237 				this.write(prefix);
1238 				this.write("=\"");
1239 			}
1240 			writeEsc(ch, 0, ch.length, true);
1241 			this.write('\"');
1242 		}
1243 	}
1244 
1245 }
1246 
1247 // end of XMLWriter.java