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