src/share/jaxws_classes/com/sun/xml/internal/txw2/output/XMLWriter.java

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

mercurial