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

Thu, 12 Oct 2017 19:44:07 +0800

author
aoqi
date
Thu, 12 Oct 2017 19:44:07 +0800
changeset 760
e530533619ec
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     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  */
    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.bind.marshaller;
    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;
    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;
    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 {
   259     ////////////////////////////////////////////////////////////////////
   260     // Constructors.
   261     ////////////////////////////////////////////////////////////////////
   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     }
   283     public XMLWriter (Writer writer, String encoding ) {
   284         this( writer, encoding, DumbEscapeHandler.theInstance );
   285     }
   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     }
   304     ////////////////////////////////////////////////////////////////////
   305     // Public methods.
   306     ////////////////////////////////////////////////////////////////////
   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     }
   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     }
   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     }
   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     }
   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     }
   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     }
   404     ////////////////////////////////////////////////////////////////////
   405     // Methods from org.xml.sax.ContentHandler.
   406     ////////////////////////////////////////////////////////////////////
   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();
   424             if(writeXmlDecl) {
   425                 String e="";
   426                 if(encoding!=null)
   427                     e = " encoding=\""+encoding+'\"';
   429                 writeXmlDecl("<?xml version=\"1.0\""+e +" standalone=\"yes\"?>");
   430             }
   432             if(header!=null)
   433                 write(header);
   435             super.startDocument();
   436         } catch( IOException e ) {
   437             throw new SAXException(e);
   438         }
   439     }
   441     protected void writeXmlDecl(String decl) throws IOException {
   442         write(decl);
   443     }
   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     }
   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();
   498             write('<');
   499             write(qName);
   500             writeAttributes(atts);
   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             }
   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     }
   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     }
   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     }
   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     }
   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     }
   667     ////////////////////////////////////////////////////////////////////
   668     // Convenience methods.
   669     ////////////////////////////////////////////////////////////////////
   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     }
   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     }
   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     }
   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     }
   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     }
   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     }
   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     }
   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     }
   886     ////////////////////////////////////////////////////////////////////
   887     // Internal methods.
   888     ////////////////////////////////////////////////////////////////////
   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     }
   903     /**
   904      * Write a raw string.
   905      */
   906     protected final void write(String s) throws IOException {
   907         output.write(s);
   908     }
   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     }
   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     }
   948     ////////////////////////////////////////////////////////////////////
   949     // Constants.
   950     ////////////////////////////////////////////////////////////////////
   952     private final Attributes EMPTY_ATTS = new AttributesImpl();
   956     ////////////////////////////////////////////////////////////////////
   957     // Internal state.
   958     ////////////////////////////////////////////////////////////////////
   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;
   971     private final CharacterEscapeHandler escapeHandler;
   973     private boolean startTagIsClosed = true;
   974 }
   976 // end of XMLWriter.java

mercurial