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

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

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

merge

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

mercurial