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

Fri, 23 Aug 2013 09:57:21 +0100

author
mkos
date
Fri, 23 Aug 2013 09:57:21 +0100
changeset 397
b99d7e355d4b
parent 286
f50545b5e2f1
child 637
9c07ef4934dd
permissions
-rw-r--r--

8022885: Update JAX-WS RI integration to 2.2.9-b14140
8013016: Rebase 8009009 against the latest jdk8/jaxws
Reviewed-by: alanb, chegar

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

mercurial