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

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 397
b99d7e355d4b
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     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  */
    26 // @@3RD PARTY CODE@@
    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.
    32 // Id: XMLWriter.java,v 1.5 2000/09/17 01:08:16 david Exp
    34 package com.sun.xml.internal.txw2.output;
    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;
    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;
    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     ////////////////////////////////////////////////////////////////////
   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     }
   295     public XMLWriter (Writer writer, String encoding ) {
   296         this( writer, encoding, DumbEscapeHandler.theInstance );
   297     }
   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     }
   316     ////////////////////////////////////////////////////////////////////
   317     // Public methods.
   318     ////////////////////////////////////////////////////////////////////
   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     }
   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     }
   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     }
   385     public void setEncoding(String encoding) {
   386         this.encoding = encoding;
   387     }
   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     }
   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     }
   414     private final HashMap locallyDeclaredPrefix = new HashMap();
   415     public void startPrefixMapping( String prefix, String uri ) throws SAXException {
   416         locallyDeclaredPrefix.put(prefix,uri);
   417     }
   420     ////////////////////////////////////////////////////////////////////
   421     // Methods from org.xml.sax.ContentHandler.
   422     ////////////////////////////////////////////////////////////////////
   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();
   440             if(writeXmlDecl) {
   441                 String e="";
   442                 if(encoding!=null)
   443                     e = " encoding=\""+encoding+"\"";
   445                 write("<?xml version=\"1.0\""+e+" standalone=\"yes\"?>\n");
   446             }
   448             if(header!=null)
   449                 write(header);
   451             super.startDocument();
   452         } catch( IOException e ) {
   453             throw new SAXException(e);
   454         }
   455     }
   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     }
   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();
   519             write('<');
   520             writeName(uri, localName, qName, true);
   521             writeAttributes(atts);
   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             }
   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     }
   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     }
   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     }
   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     }
   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     }
   696     ////////////////////////////////////////////////////////////////////
   697     // Convenience methods.
   698     ////////////////////////////////////////////////////////////////////
   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     }
   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     }
   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     }
   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     }
   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     }
   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     }
   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     }
   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     }
   914     public void startDTD(String name, String publicId, String systemId) throws SAXException {
   915     }
   917     public void endDTD() throws SAXException {
   918     }
   920     public void startEntity(String name) throws SAXException {
   921     }
   923     public void endEntity(String name) throws SAXException {
   924     }
   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     }
   939     public void endCDATA() throws SAXException {
   940         try {
   941             inCDATA = false;
   942             write("]]>");
   943         } catch (IOException e) {
   944             throw new SAXException(e);
   945         }
   946     }
   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     }
   960     ////////////////////////////////////////////////////////////////////
   961     // Internal methods.
   962     ////////////////////////////////////////////////////////////////////
   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     }
   977     /**
   978      * Write a raw string.
   979      */
   980     private void write (String s) throws IOException {
   981         output.write(s);
   982     }
   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('"');
  1009     /**
  1010      * Write an array of data characters with escaping.
  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
  1024         escapeHandler.escape(ch, start, length, isAttVal, output);
  1028     /**
  1029      * Write an element or attribute name.
  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
  1041         write(qName);
  1046     ////////////////////////////////////////////////////////////////////
  1047     // Constants.
  1048     ////////////////////////////////////////////////////////////////////
  1050     private final Attributes EMPTY_ATTS = new AttributesImpl();
  1054     ////////////////////////////////////////////////////////////////////
  1055     // Internal state.
  1056     ////////////////////////////////////////////////////////////////////
  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;
  1070     private final CharacterEscapeHandler escapeHandler;
  1072     private boolean startTagIsClosed = true;
  1075 // end of XMLWriter.java

mercurial