src/share/jaxws_classes/com/sun/xml/internal/bind/marshaller/XMLWriter.java

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

mercurial