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

Save This Page
Home » openjdk-7 » com.sun.xml.internal » txw2 » output » [javadoc | source]