1 /*
   2  * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 // @@3RD PARTY CODE@@
  27 
  28 // XMLWriter.java - serialize an XML document.
  29 // Written by David Megginson, david@megginson.com
  30 // NO WARRANTY!  This class is in the public domain.
  31 
  32 // Id: XMLWriter.java,v 1.5 2000/09/17 01:08:16 david Exp
  33 
  34 package com.sun.xml.internal.txw2.output;
  35 
  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;
  41 
  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;
  48 
  49 
  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>{@code
  97  *  <?xml version="1.0" standalone="yes"?>
  98  *
  99  * <greeting>Hello, world!</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>{@code
 131  * <item>1</item><item>3</item><item>3</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>{@code
 160  * <?xml version="1.0" standalone="yes"?>
 161  *
 162  * <_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 #startPrefixMapping(String, String)} 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>{@code
 192  * <?xml version="1.0" standalone="yes"?>
 193  *
 194  * <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>{@code
 209  * <?xml version="1.0" standalone="yes"?>
 210  *
 211  * <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>{@code
 220  * <xml version="1.0" standalone="yes"?>
 221  *
 222  * <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
 223  *  <rdf:Description about="http://www.foo.com/ids/books/12345">
 224  *   <dc:title xmlns:dc="http://www.purl.org/dc/">A Dark Night</dc:title>
 225  *   <dc:creator xmlns:dc="http://www.purl.org/dc/">Jane Smith</dc:title>
 226  *   <dc:date xmlns:dc="http://www.purl.org/dc/">2000-09-09</dc:title>
 227  *  </rdf:Description>
 228  * </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>{@code
 247  * <xml version="1.0" standalone="yes"?>
 248  *
 249  * <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 250  *             xmlns:dc="http://www.purl.org/dc/">
 251  *  <rdf:Description about="http://www.foo.com/ids/books/12345">
 252  *   <dc:title>A Dark Night</dc:title>
 253  *   <dc:creator>Jane Smith</dc:title>
 254  *   <dc:date>2000-09-09</dc:title>
 255  *  </rdf:Description>
 256  * </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 JAXB 1.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     ////////////////////////////////////////////////////////////////////
 274 
 275 
 276 
 277 
 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     }
 294 
 295     public XMLWriter (Writer writer, String encoding ) {
 296         this( writer, encoding, DumbEscapeHandler.theInstance );
 297     }
 298 
 299 
 300 
 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     }
 313 
 314 
 315 
 316     ////////////////////////////////////////////////////////////////////
 317     // Public methods.
 318     ////////////////////////////////////////////////////////////////////
 319 
 320 
 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     }
 345 
 346 
 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     }
 366 
 367 
 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     }
 384 
 385     public void setEncoding(String encoding) {
 386         this.encoding = encoding;
 387     }
 388 
 389     /**
 390      * Set whether the writer should print out the XML declaration
 391      * ({@code <?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     }
 398 
 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     }
 412 
 413 
 414     private final HashMap locallyDeclaredPrefix = new HashMap();
 415     public void startPrefixMapping( String prefix, String uri ) throws SAXException {
 416         locallyDeclaredPrefix.put(prefix,uri);
 417     }
 418 
 419 
 420     ////////////////////////////////////////////////////////////////////
 421     // Methods from org.xml.sax.ContentHandler.
 422     ////////////////////////////////////////////////////////////////////
 423 
 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();
 439 
 440             if(writeXmlDecl) {
 441                 String e="";
 442                 if(encoding!=null)
 443                     e = " encoding=\""+encoding+"\"";
 444 
 445                 write("<?xml version=\"1.0\""+e+" standalone=\"yes\"?>\n");
 446             }
 447 
 448             if(header!=null)
 449                 write(header);
 450 
 451             super.startDocument();
 452         } catch( IOException e ) {
 453             throw new SAXException(e);
 454         }
 455     }
 456 
 457 
 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     }
 487 
 488 
 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();
 518 
 519             write('<');
 520             writeName(uri, localName, qName, true);
 521             writeAttributes(atts);
 522 
 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             }
 547 
 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     }
 558 
 559 
 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     }
 600 
 601 
 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     }
 632 
 633 
 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     }
 657 
 658 
 659 
 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     }
 693 
 694 
 695 
 696     ////////////////////////////////////////////////////////////////////
 697     // Convenience methods.
 698     ////////////////////////////////////////////////////////////////////
 699 
 700 
 701 
 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     }
 723 
 724 
 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     }
 745 
 746 
 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     }
 766 
 767 
 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     }
 787 
 788 
 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     }
 823 
 824 
 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     }
 854 
 855 
 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     }
 885 
 886 
 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     }
 912 
 913 
 914     public void startDTD(String name, String publicId, String systemId) throws SAXException {
 915     }
 916 
 917     public void endDTD() throws SAXException {
 918     }
 919 
 920     public void startEntity(String name) throws SAXException {
 921     }
 922 
 923     public void endEntity(String name) throws SAXException {
 924     }
 925 
 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     }
 938 
 939     public void endCDATA() throws SAXException {
 940         try {
 941             inCDATA = false;
 942             write("]]>");
 943         } catch (IOException e) {
 944             throw new SAXException(e);
 945         }
 946     }
 947 
 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     }
 957 
 958 
 959 
 960     ////////////////////////////////////////////////////////////////////
 961     // Internal methods.
 962     ////////////////////////////////////////////////////////////////////
 963 
 964 
 965 
 966 
 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     }
 975 
 976 
 977     /**
 978      * Write a raw string.
 979      */
 980     private void write (String s) throws IOException {
 981         output.write(s);
 982     }
 983 
 984 
 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('"');
1005         }
1006     }
1007 
1008 
1009     /**
1010      * Write an array of data characters with escaping.
1011      *
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
1023     {
1024         escapeHandler.escape(ch, start, length, isAttVal, output);
1025     }
1026 
1027 
1028     /**
1029      * Write an element or attribute name.
1030      *
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
1040     {
1041         write(qName);
1042     }
1043 
1044 
1045 
1046     ////////////////////////////////////////////////////////////////////
1047     // Constants.
1048     ////////////////////////////////////////////////////////////////////
1049 
1050     private final Attributes EMPTY_ATTS = new AttributesImpl();
1051 
1052 
1053 
1054     ////////////////////////////////////////////////////////////////////
1055     // Internal state.
1056     ////////////////////////////////////////////////////////////////////
1057 
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;
1069 
1070     private final CharacterEscapeHandler escapeHandler;
1071 
1072     private boolean startTagIsClosed = true;
1073 }
1074 
1075 // end of XMLWriter.java
--- EOF ---