001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: // @@3RD PARTY CODE@@
038: // XMLWriter.java - serialize an XML document.
039: // Written by David Megginson, david@megginson.com
040: // NO WARRANTY! This class is in the public domain.
041: // Id: XMLWriter.java,v 1.5 2000/09/17 01:08:16 david Exp
042: package com.sun.xml.bind.marshaller;
043:
044: import java.io.IOException;
045: import java.io.OutputStreamWriter;
046: import java.io.Writer;
047: import java.util.HashMap;
048: import java.util.Map;
049:
050: import org.xml.sax.Attributes;
051: import org.xml.sax.SAXException;
052: import org.xml.sax.helpers.AttributesImpl;
053: import org.xml.sax.helpers.XMLFilterImpl;
054:
055: /**
056: * Filter to write an XML document from a SAX event stream.
057: *
058: * <p>This class can be used by itself or as part of a SAX event
059: * stream: it takes as input a series of SAX2 ContentHandler
060: * events and uses the information in those events to write
061: * an XML document. Since this class is a filter, it can also
062: * pass the events on down a filter chain for further processing
063: * (you can use the XMLWriter to take a snapshot of the current
064: * state at any point in a filter chain), and it can be
065: * used directly as a ContentHandler for a SAX2 XMLReader.</p>
066: *
067: * <p>The client creates a document by invoking the methods for
068: * standard SAX2 events, always beginning with the
069: * {@link #startDocument startDocument} method and ending with
070: * the {@link #endDocument endDocument} method. There are convenience
071: * methods provided so that clients to not have to create empty
072: * attribute lists or provide empty strings as parameters; for
073: * example, the method invocation</p>
074: *
075: * <pre>
076: * w.startElement("foo");
077: * </pre>
078: *
079: * <p>is equivalent to the regular SAX2 ContentHandler method</p>
080: *
081: * <pre>
082: * w.startElement("", "foo", "", new AttributesImpl());
083: * </pre>
084: *
085: * <p>Except that it is more efficient because it does not allocate
086: * a new empty attribute list each time. The following code will send
087: * a simple XML document to standard output:</p>
088: *
089: * <pre>
090: * XMLWriter w = new XMLWriter();
091: *
092: * w.startDocument();
093: * w.startElement("greeting");
094: * w.characters("Hello, world!");
095: * w.endElement("greeting");
096: * w.endDocument();
097: * </pre>
098: *
099: * <p>The resulting document will look like this:</p>
100: *
101: * <pre>
102: * <?xml version="1.0" standalone="yes"?>
103: *
104: * <greeting>Hello, world!</greeting>
105: * </pre>
106: *
107: * <p>In fact, there is an even simpler convenience method,
108: * <var>dataElement</var>, designed for writing elements that
109: * contain only character data, so the code to generate the
110: * document could be shortened to</p>
111: *
112: * <pre>
113: * XMLWriter w = new XMLWriter();
114: *
115: * w.startDocument();
116: * w.dataElement("greeting", "Hello, world!");
117: * w.endDocument();
118: * </pre>
119: *
120: * <h2>Whitespace</h2>
121: *
122: * <p>According to the XML Recommendation, <em>all</em> whitespace
123: * in an XML document is potentially significant to an application,
124: * so this class never adds newlines or indentation. If you
125: * insert three elements in a row, as in</p>
126: *
127: * <pre>
128: * w.dataElement("item", "1");
129: * w.dataElement("item", "2");
130: * w.dataElement("item", "3");
131: * </pre>
132: *
133: * <p>you will end up with</p>
134: *
135: * <pre>
136: * <item>1</item><item>3</item><item>3</item>
137: * </pre>
138: *
139: * <p>You need to invoke one of the <var>characters</var> methods
140: * explicitly to add newlines or indentation. Alternatively, you
141: * can use {@link DataWriter}, which
142: * is derived from this class -- it is optimized for writing
143: * purely data-oriented (or field-oriented) XML, and does automatic
144: * linebreaks and indentation (but does not support mixed content
145: * properly).</p>
146: *
147: *
148: * <h2>Namespace Support</h2>
149: *
150: * <p>The writer contains extensive support for XML Namespaces, so that
151: * a client application does not have to keep track of prefixes and
152: * supply <var>xmlns</var> attributes. By default, the XML writer will
153: * generate Namespace declarations in the form _NS1, _NS2, etc., wherever
154: * they are needed, as in the following example:</p>
155: *
156: * <pre>
157: * w.startDocument();
158: * w.emptyElement("http://www.foo.com/ns/", "foo");
159: * w.endDocument();
160: * </pre>
161: *
162: * <p>The resulting document will look like this:</p>
163: *
164: * <pre>
165: * <?xml version="1.0" standalone="yes"?>
166: *
167: * <_NS1:foo xmlns:_NS1="http://www.foo.com/ns/"/>
168: * </pre>
169: *
170: * <p>In many cases, document authors will prefer to choose their
171: * own prefixes rather than using the (ugly) default names. The
172: * XML writer allows two methods for selecting prefixes:</p>
173: *
174: * <ol>
175: * <li>the qualified name</li>
176: * </ol>
177: *
178: * <p>Whenever the XML writer finds a new Namespace URI, it checks
179: * to see if a qualified (prefixed) name is also available; if so
180: * it attempts to use the name's prefix (as long as the prefix is
181: * not already in use for another Namespace URI).</p>
182: *
183: * <p>The resulting document will look like this:</p>
184: *
185: * <pre>
186: * <?xml version="1.0" standalone="yes"?>
187: *
188: * <foo:foo xmlns:foo="http://www.foo.com/ns/"/>
189: * </pre>
190: *
191: * <p>The default Namespace simply uses an empty string as the prefix:</p>
192: *
193: * <pre>
194: * w.setPrefix("http://www.foo.com/ns/", "");
195: * w.startDocument();
196: * w.emptyElement("http://www.foo.com/ns/", "foo");
197: * w.endDocument();
198: * </pre>
199: *
200: * <p>The resulting document will look like this:</p>
201: *
202: * <pre>
203: * <?xml version="1.0" standalone="yes"?>
204: *
205: * <foo xmlns="http://www.foo.com/ns/"/>
206: * </pre>
207: *
208: * <p>By default, the XML writer will not declare a Namespace until
209: * it is actually used. Sometimes, this approach will create
210: * a large number of Namespace declarations, as in the following
211: * example:</p>
212: *
213: * <pre>
214: * <xml version="1.0" standalone="yes"?>
215: *
216: * <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
217: * <rdf:Description about="http://www.foo.com/ids/books/12345">
218: * <dc:title xmlns:dc="http://www.purl.org/dc/">A Dark Night</dc:title>
219: * <dc:creator xmlns:dc="http://www.purl.org/dc/">Jane Smith</dc:title>
220: * <dc:date xmlns:dc="http://www.purl.org/dc/">2000-09-09</dc:title>
221: * </rdf:Description>
222: * </rdf:RDF>
223: * </pre>
224: *
225: * <p>The "rdf" prefix is declared only once, because the RDF Namespace
226: * is used by the root element and can be inherited by all of its
227: * descendants; the "dc" prefix, on the other hand, is declared three
228: * times, because no higher element uses the Namespace. To solve this
229: * problem, you can instruct the XML writer to predeclare Namespaces
230: * on the root element even if they are not used there:</p>
231: *
232: * <pre>
233: * w.forceNSDecl("http://www.purl.org/dc/");
234: * </pre>
235: *
236: * <p>Now, the "dc" prefix will be declared on the root element even
237: * though it's not needed there, and can be inherited by its
238: * descendants:</p>
239: *
240: * <pre>
241: * <xml version="1.0" standalone="yes"?>
242: *
243: * <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
244: * xmlns:dc="http://www.purl.org/dc/">
245: * <rdf:Description about="http://www.foo.com/ids/books/12345">
246: * <dc:title>A Dark Night</dc:title>
247: * <dc:creator>Jane Smith</dc:title>
248: * <dc:date>2000-09-09</dc:title>
249: * </rdf:Description>
250: * </rdf:RDF>
251: * </pre>
252: *
253: * <p>This approach is also useful for declaring Namespace prefixes
254: * that be used by qualified names appearing in attribute values or
255: * character data.</p>
256: *
257: * @author David Megginson, david@megginson.com
258: * @version 0.2
259: * @since JAXB1.0
260: * @see org.xml.sax.XMLFilter
261: * @see org.xml.sax.ContentHandler
262: */
263: public class XMLWriter extends XMLFilterImpl {
264:
265: ////////////////////////////////////////////////////////////////////
266: // Constructors.
267: ////////////////////////////////////////////////////////////////////
268:
269: /**
270: * Create a new XML writer.
271: *
272: * <p>Write to the writer provided.</p>
273: *
274: * @param writer
275: * The output destination, or null to use standard output.
276: * @param encoding
277: * If non-null string is specified, it is written as a part
278: * of the XML declaration.
279: */
280: public XMLWriter(Writer writer, String encoding,
281: CharacterEscapeHandler _escapeHandler) {
282: init(writer, encoding);
283: this .escapeHandler = _escapeHandler;
284: }
285:
286: public XMLWriter(Writer writer, String encoding) {
287: this (writer, encoding, DumbEscapeHandler.theInstance);
288: }
289:
290: /**
291: * Internal initialization method.
292: *
293: * <p>All of the public constructors invoke this method.
294: *
295: * @param writer The output destination, or null to use
296: * standard output.
297: */
298: private void init(Writer writer, String encoding) {
299: setOutput(writer, encoding);
300: }
301:
302: ////////////////////////////////////////////////////////////////////
303: // Public methods.
304: ////////////////////////////////////////////////////////////////////
305:
306: /**
307: * Reset the writer.
308: *
309: * <p>This method is especially useful if the writer throws an
310: * exception before it is finished, and you want to reuse the
311: * writer for a new document. It is usually a good idea to
312: * invoke {@link #flush flush} before resetting the writer,
313: * to make sure that no output is lost.</p>
314: *
315: * <p>This method is invoked automatically by the
316: * {@link #startDocument startDocument} method before writing
317: * a new document.</p>
318: *
319: * <p><strong>Note:</strong> this method will <em>not</em>
320: * clear the prefix or URI information in the writer or
321: * the selected output writer.</p>
322: *
323: * @see #flush()
324: */
325: public void reset() {
326: elementLevel = 0;
327: startTagIsClosed = true;
328: }
329:
330: /**
331: * Flush the output.
332: *
333: * <p>This method flushes the output stream. It is especially useful
334: * when you need to make certain that the entire document has
335: * been written to output but do not want to close the output
336: * stream.</p>
337: *
338: * <p>This method is invoked automatically by the
339: * {@link #endDocument endDocument} method after writing a
340: * document.</p>
341: *
342: * @see #reset()
343: */
344: public void flush() throws IOException {
345: output.flush();
346: }
347:
348: /**
349: * Set a new output destination for the document.
350: *
351: * @param writer The output destination, or null to use
352: * standard output.
353: * @see #flush()
354: */
355: public void setOutput(Writer writer, String _encoding) {
356: if (writer == null) {
357: output = new OutputStreamWriter(System.out);
358: } else {
359: output = writer;
360: }
361: encoding = _encoding;
362: }
363:
364: /**
365: * Set whether the writer should print out the XML declaration
366: * (<?xml version='1.0' ... ?>).
367: * <p>
368: * This option is set to true by default.
369: */
370: public void setXmlDecl(boolean _writeXmlDecl) {
371: this .writeXmlDecl = _writeXmlDecl;
372: }
373:
374: /**
375: * Sets the header string.
376: *
377: * This string will be written right after the xml declaration
378: * without any escaping. Useful for generating a boiler-plate
379: * DOCTYPE decl, PIs, and comments.
380: *
381: * @param _header
382: * passing null will work as if the empty string is passed.
383: */
384: public void setHeader(String _header) {
385: this .header = _header;
386: }
387:
388: private final HashMap<String, String> locallyDeclaredPrefix = new HashMap<String, String>();
389:
390: public void startPrefixMapping(String prefix, String uri)
391: throws SAXException {
392: locallyDeclaredPrefix.put(prefix, uri);
393: }
394:
395: ////////////////////////////////////////////////////////////////////
396: // Methods from org.xml.sax.ContentHandler.
397: ////////////////////////////////////////////////////////////////////
398:
399: /**
400: * Write the XML declaration at the beginning of the document.
401: *
402: * Pass the event on down the filter chain for further processing.
403: *
404: * @exception org.xml.sax.SAXException If there is an error
405: * writing the XML declaration, or if a handler further down
406: * the filter chain raises an exception.
407: * @see org.xml.sax.ContentHandler#startDocument()
408: */
409: public void startDocument() throws SAXException {
410: try {
411: reset();
412:
413: if (writeXmlDecl) {
414: String e = "";
415: if (encoding != null)
416: e = " encoding=\"" + encoding + '\"';
417:
418: writeXmlDecl("<?xml version=\"1.0\"" + e
419: + " standalone=\"yes\"?>");
420: }
421:
422: if (header != null)
423: write(header);
424:
425: super .startDocument();
426: } catch (IOException e) {
427: throw new SAXException(e);
428: }
429: }
430:
431: protected void writeXmlDecl(String decl) throws IOException {
432: write(decl);
433: }
434:
435: /**
436: * Write a newline at the end of the document.
437: *
438: * Pass the event on down the filter chain for further processing.
439: *
440: * @exception org.xml.sax.SAXException If there is an error
441: * writing the newline, or if a handler further down
442: * the filter chain raises an exception.
443: * @see org.xml.sax.ContentHandler#endDocument()
444: */
445: public void endDocument() throws SAXException {
446: try {
447: super .endDocument();
448: flush();
449: } catch (IOException e) {
450: throw new SAXException(e);
451: }
452: }
453:
454: /**
455: * Write a start tag.
456: *
457: * Pass the event on down the filter chain for further processing.
458: *
459: * @param uri The Namespace URI, or the empty string if none
460: * is available.
461: * @param localName The element's local (unprefixed) name (required).
462: * @param qName The element's qualified (prefixed) name, or the
463: * empty string is none is available. This method will
464: * use the qName as a template for generating a prefix
465: * if necessary, but it is not guaranteed to use the
466: * same qName.
467: * @param atts The element's attribute list (must not be null).
468: * @exception org.xml.sax.SAXException If there is an error
469: * writing the start tag, or if a handler further down
470: * the filter chain raises an exception.
471: * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
472: */
473: public void startElement(String uri, String localName,
474: String qName, Attributes atts) throws SAXException {
475: try {
476: if (!startTagIsClosed) {
477: write(">");
478: }
479: elementLevel++;
480: // nsSupport.pushContext();
481:
482: write('<');
483: write(qName);
484: writeAttributes(atts);
485:
486: // declare namespaces specified by the startPrefixMapping methods
487: if (!locallyDeclaredPrefix.isEmpty()) {
488: for (Map.Entry<String, String> e : locallyDeclaredPrefix
489: .entrySet()) {
490: String p = e.getKey();
491: String u = e.getValue();
492: if (u == null) {
493: u = "";
494: }
495: write(' ');
496: if ("".equals(p)) {
497: write("xmlns=\"");
498: } else {
499: write("xmlns:");
500: write(p);
501: write("=\"");
502: }
503: char ch[] = u.toCharArray();
504: writeEsc(ch, 0, ch.length, true);
505: write('\"');
506: }
507: locallyDeclaredPrefix.clear(); // clear the contents
508: }
509:
510: // if (elementLevel == 1) {
511: // forceNSDecls();
512: // }
513: // writeNSDecls();
514: super .startElement(uri, localName, qName, atts);
515: startTagIsClosed = false;
516: } catch (IOException e) {
517: throw new SAXException(e);
518: }
519: }
520:
521: /**
522: * Write an end tag.
523: *
524: * Pass the event on down the filter chain for further processing.
525: *
526: * @param uri The Namespace URI, or the empty string if none
527: * is available.
528: * @param localName The element's local (unprefixed) name (required).
529: * @param qName The element's qualified (prefixed) name, or the
530: * empty string is none is available. This method will
531: * use the qName as a template for generating a prefix
532: * if necessary, but it is not guaranteed to use the
533: * same qName.
534: * @exception org.xml.sax.SAXException If there is an error
535: * writing the end tag, or if a handler further down
536: * the filter chain raises an exception.
537: * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
538: */
539: public void endElement(String uri, String localName, String qName)
540: throws SAXException {
541: try {
542: if (startTagIsClosed) {
543: write("</");
544: write(qName);
545: write('>');
546: } else {
547: write("/>");
548: startTagIsClosed = true;
549: }
550: super .endElement(uri, localName, qName);
551: // nsSupport.popContext();
552: elementLevel--;
553: } catch (IOException e) {
554: throw new SAXException(e);
555: }
556: }
557:
558: /**
559: * Write character data.
560: *
561: * Pass the event on down the filter chain for further processing.
562: *
563: * @param ch The array of characters to write.
564: * @param start The starting position in the array.
565: * @param len The number of characters to write.
566: * @exception org.xml.sax.SAXException If there is an error
567: * writing the characters, or if a handler further down
568: * the filter chain raises an exception.
569: * @see org.xml.sax.ContentHandler#characters(char[], int, int)
570: */
571: public void characters(char ch[], int start, int len)
572: throws SAXException {
573: try {
574: if (!startTagIsClosed) {
575: write('>');
576: startTagIsClosed = true;
577: }
578: writeEsc(ch, start, len, false);
579: super .characters(ch, start, len);
580: } catch (IOException e) {
581: throw new SAXException(e);
582: }
583: }
584:
585: /**
586: * Write ignorable whitespace.
587: *
588: * Pass the event on down the filter chain for further processing.
589: *
590: * @param ch The array of characters to write.
591: * @param start The starting position in the array.
592: * @param length The number of characters to write.
593: * @exception org.xml.sax.SAXException If there is an error
594: * writing the whitespace, or if a handler further down
595: * the filter chain raises an exception.
596: * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
597: */
598: public void ignorableWhitespace(char ch[], int start, int length)
599: throws SAXException {
600: try {
601: writeEsc(ch, start, length, false);
602: super .ignorableWhitespace(ch, start, length);
603: } catch (IOException e) {
604: throw new SAXException(e);
605: }
606: }
607:
608: /**
609: * Write a processing instruction.
610: *
611: * Pass the event on down the filter chain for further processing.
612: *
613: * @param target The PI target.
614: * @param data The PI data.
615: * @exception org.xml.sax.SAXException If there is an error
616: * writing the PI, or if a handler further down
617: * the filter chain raises an exception.
618: * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
619: */
620: public void processingInstruction(String target, String data)
621: throws SAXException {
622: try {
623: if (!startTagIsClosed) {
624: write('>');
625: startTagIsClosed = true;
626: }
627: write("<?");
628: write(target);
629: write(' ');
630: write(data);
631: write("?>");
632: if (elementLevel < 1) {
633: write('\n');
634: }
635: super .processingInstruction(target, data);
636: } catch (IOException e) {
637: throw new SAXException(e);
638: }
639: }
640:
641: ////////////////////////////////////////////////////////////////////
642: // Convenience methods.
643: ////////////////////////////////////////////////////////////////////
644:
645: /**
646: * Start a new element without a qname or attributes.
647: *
648: * <p>This method will provide a default empty attribute
649: * list and an empty string for the qualified name.
650: * It invokes {@link
651: * #startElement(String, String, String, Attributes)}
652: * directly.</p>
653: *
654: * @param uri The element's Namespace URI.
655: * @param localName The element's local name.
656: * @exception org.xml.sax.SAXException If there is an error
657: * writing the start tag, or if a handler further down
658: * the filter chain raises an exception.
659: * @see #startElement(String, String, String, Attributes)
660: */
661: public void startElement(String uri, String localName)
662: throws SAXException {
663: startElement(uri, localName, "", EMPTY_ATTS);
664: }
665:
666: /**
667: * Start a new element without a qname, attributes or a Namespace URI.
668: *
669: * <p>This method will provide an empty string for the
670: * Namespace URI, and empty string for the qualified name,
671: * and a default empty attribute list. It invokes
672: * #startElement(String, String, String, Attributes)}
673: * directly.</p>
674: *
675: * @param localName The element's local name.
676: * @exception org.xml.sax.SAXException If there is an error
677: * writing the start tag, or if a handler further down
678: * the filter chain raises an exception.
679: * @see #startElement(String, String, String, Attributes)
680: */
681: public void startElement(String localName) throws SAXException {
682: startElement("", localName, "", EMPTY_ATTS);
683: }
684:
685: /**
686: * End an element without a qname.
687: *
688: * <p>This method will supply an empty string for the qName.
689: * It invokes {@link #endElement(String, String, String)}
690: * directly.</p>
691: *
692: * @param uri The element's Namespace URI.
693: * @param localName The element's local name.
694: * @exception org.xml.sax.SAXException If there is an error
695: * writing the end tag, or if a handler further down
696: * the filter chain raises an exception.
697: * @see #endElement(String, String, String)
698: */
699: public void endElement(String uri, String localName)
700: throws SAXException {
701: endElement(uri, localName, "");
702: }
703:
704: /**
705: * End an element without a Namespace URI or qname.
706: *
707: * <p>This method will supply an empty string for the qName
708: * and an empty string for the Namespace URI.
709: * It invokes {@link #endElement(String, String, String)}
710: * directly.</p>
711: *
712: * @param localName The element's local name.
713: * @exception org.xml.sax.SAXException If there is an error
714: * writing the end tag, or if a handler further down
715: * the filter chain raises an exception.
716: * @see #endElement(String, String, String)
717: */
718: public void endElement(String localName) throws SAXException {
719: endElement("", localName, "");
720: }
721:
722: /**
723: * Write an element with character data content.
724: *
725: * <p>This is a convenience method to write a complete element
726: * with character data content, including the start tag
727: * and end tag.</p>
728: *
729: * <p>This method invokes
730: * {@link #startElement(String, String, String, Attributes)},
731: * followed by
732: * {@link #characters(String)}, followed by
733: * {@link #endElement(String, String, String)}.</p>
734: *
735: * @param uri The element's Namespace URI.
736: * @param localName The element's local name.
737: * @param qName The element's default qualified name.
738: * @param atts The element's attributes.
739: * @param content The character data content.
740: * @exception org.xml.sax.SAXException If there is an error
741: * writing the empty tag, or if a handler further down
742: * the filter chain raises an exception.
743: * @see #startElement(String, String, String, Attributes)
744: * @see #characters(String)
745: * @see #endElement(String, String, String)
746: */
747: public void dataElement(String uri, String localName, String qName,
748: Attributes atts, String content) throws SAXException {
749: startElement(uri, localName, qName, atts);
750: characters(content);
751: endElement(uri, localName, qName);
752: }
753:
754: /**
755: * Write an element with character data content but no attributes.
756: *
757: * <p>This is a convenience method to write a complete element
758: * with character data content, including the start tag
759: * and end tag. This method provides an empty string
760: * for the qname and an empty attribute list.</p>
761: *
762: * <p>This method invokes
763: * {@link #startElement(String, String, String, Attributes)},
764: * followed by
765: * {@link #characters(String)}, followed by
766: * {@link #endElement(String, String, String)}.</p>
767: *
768: * @param uri The element's Namespace URI.
769: * @param localName The element's local name.
770: * @param content The character data content.
771: * @exception org.xml.sax.SAXException If there is an error
772: * writing the empty tag, or if a handler further down
773: * the filter chain raises an exception.
774: * @see #startElement(String, String, String, Attributes)
775: * @see #characters(String)
776: * @see #endElement(String, String, String)
777: */
778: public void dataElement(String uri, String localName, String content)
779: throws SAXException {
780: dataElement(uri, localName, "", EMPTY_ATTS, content);
781: }
782:
783: /**
784: * Write an element with character data content but no attributes or Namespace URI.
785: *
786: * <p>This is a convenience method to write a complete element
787: * with character data content, including the start tag
788: * and end tag. The method provides an empty string for the
789: * Namespace URI, and empty string for the qualified name,
790: * and an empty attribute list.</p>
791: *
792: * <p>This method invokes
793: * {@link #startElement(String, String, String, Attributes)},
794: * followed by
795: * {@link #characters(String)}, followed by
796: * {@link #endElement(String, String, String)}.</p>
797: *
798: * @param localName The element's local name.
799: * @param content The character data content.
800: * @exception org.xml.sax.SAXException If there is an error
801: * writing the empty tag, or if a handler further down
802: * the filter chain raises an exception.
803: * @see #startElement(String, String, String, Attributes)
804: * @see #characters(String)
805: * @see #endElement(String, String, String)
806: */
807: public void dataElement(String localName, String content)
808: throws SAXException {
809: dataElement("", localName, "", EMPTY_ATTS, content);
810: }
811:
812: /**
813: * Write a string of character data, with XML escaping.
814: *
815: * <p>This is a convenience method that takes an XML
816: * String, converts it to a character array, then invokes
817: * {@link #characters(char[], int, int)}.</p>
818: *
819: * @param data The character data.
820: * @exception org.xml.sax.SAXException If there is an error
821: * writing the string, or if a handler further down
822: * the filter chain raises an exception.
823: * @see #characters(char[], int, int)
824: */
825: public void characters(String data) throws SAXException {
826: try {
827: if (!startTagIsClosed) {
828: write('>');
829: startTagIsClosed = true;
830: }
831: char ch[] = data.toCharArray();
832: characters(ch, 0, ch.length);
833: } catch (IOException e) {
834: throw new SAXException(e);
835: }
836: }
837:
838: ////////////////////////////////////////////////////////////////////
839: // Internal methods.
840: ////////////////////////////////////////////////////////////////////
841:
842: /**
843: * Write a raw character.
844: *
845: * @param c The character to write.
846: */
847: protected final void write(char c) throws IOException {
848: output.write(c);
849: }
850:
851: /**
852: * Write a raw string.
853: */
854: protected final void write(String s) throws IOException {
855: output.write(s);
856: }
857:
858: /**
859: * Write out an attribute list, escaping values.
860: *
861: * The names will have prefixes added to them.
862: *
863: * @param atts The attribute list to write.
864: */
865: private void writeAttributes(Attributes atts) throws IOException {
866: int len = atts.getLength();
867: for (int i = 0; i < len; i++) {
868: char ch[] = atts.getValue(i).toCharArray();
869: write(' ');
870: write(atts.getQName(i));
871: write("=\"");
872: writeEsc(ch, 0, ch.length, true);
873: write('"');
874: }
875: }
876:
877: /**
878: * Write an array of data characters with escaping.
879: *
880: * @param ch The array of characters.
881: * @param start The starting position.
882: * @param length The number of characters to use.
883: * @param isAttVal true if this is an attribute value literal.
884: */
885: private void writeEsc(char ch[], int start, int length,
886: boolean isAttVal) throws IOException {
887: escapeHandler.escape(ch, start, length, isAttVal, output);
888: }
889:
890: ////////////////////////////////////////////////////////////////////
891: // Constants.
892: ////////////////////////////////////////////////////////////////////
893:
894: private final Attributes EMPTY_ATTS = new AttributesImpl();
895:
896: ////////////////////////////////////////////////////////////////////
897: // Internal state.
898: ////////////////////////////////////////////////////////////////////
899:
900: private int elementLevel = 0;
901: private Writer output;
902: private String encoding;
903: private boolean writeXmlDecl = true;
904: /**
905: * This string will be written right after the xml declaration
906: * without any escaping. Useful for generating a boiler-plate DOCTYPE decl
907: * , PIs, and comments.
908: */
909: private String header = null;
910:
911: private final CharacterEscapeHandler escapeHandler;
912:
913: private boolean startTagIsClosed = true;
914: }
915:
916: // end of XMLWriter.java
|