1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/jaxws_classes/com/sun/xml/internal/bind/marshaller/XMLWriter.java Wed Apr 27 01:27:09 2016 +0800 1.3 @@ -0,0 +1,976 @@ 1.4 +/* 1.5 + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +// @@3RD PARTY CODE@@ 1.30 + 1.31 +// XMLWriter.java - serialize an XML document. 1.32 +// Written by David Megginson, david@megginson.com 1.33 +// NO WARRANTY! This class is in the public domain. 1.34 + 1.35 +// Id: XMLWriter.java,v 1.5 2000/09/17 01:08:16 david Exp 1.36 + 1.37 +package com.sun.xml.internal.bind.marshaller; 1.38 + 1.39 +import java.io.IOException; 1.40 +import java.io.OutputStreamWriter; 1.41 +import java.io.Writer; 1.42 +import java.util.HashMap; 1.43 +import java.util.Map; 1.44 + 1.45 +import org.xml.sax.Attributes; 1.46 +import org.xml.sax.SAXException; 1.47 +import org.xml.sax.helpers.AttributesImpl; 1.48 +import org.xml.sax.helpers.XMLFilterImpl; 1.49 + 1.50 + 1.51 +/** 1.52 + * Filter to write an XML document from a SAX event stream. 1.53 + * 1.54 + * <p>This class can be used by itself or as part of a SAX event 1.55 + * stream: it takes as input a series of SAX2 ContentHandler 1.56 + * events and uses the information in those events to write 1.57 + * an XML document. Since this class is a filter, it can also 1.58 + * pass the events on down a filter chain for further processing 1.59 + * (you can use the XMLWriter to take a snapshot of the current 1.60 + * state at any point in a filter chain), and it can be 1.61 + * used directly as a ContentHandler for a SAX2 XMLReader.</p> 1.62 + * 1.63 + * <p>The client creates a document by invoking the methods for 1.64 + * standard SAX2 events, always beginning with the 1.65 + * {@link #startDocument startDocument} method and ending with 1.66 + * the {@link #endDocument endDocument} method. There are convenience 1.67 + * methods provided so that clients to not have to create empty 1.68 + * attribute lists or provide empty strings as parameters; for 1.69 + * example, the method invocation</p> 1.70 + * 1.71 + * <pre> 1.72 + * w.startElement("foo"); 1.73 + * </pre> 1.74 + * 1.75 + * <p>is equivalent to the regular SAX2 ContentHandler method</p> 1.76 + * 1.77 + * <pre> 1.78 + * w.startElement("", "foo", "", new AttributesImpl()); 1.79 + * </pre> 1.80 + * 1.81 + * <p>Except that it is more efficient because it does not allocate 1.82 + * a new empty attribute list each time. The following code will send 1.83 + * a simple XML document to standard output:</p> 1.84 + * 1.85 + * <pre> 1.86 + * XMLWriter w = new XMLWriter(); 1.87 + * 1.88 + * w.startDocument(); 1.89 + * w.startElement("greeting"); 1.90 + * w.characters("Hello, world!"); 1.91 + * w.endElement("greeting"); 1.92 + * w.endDocument(); 1.93 + * </pre> 1.94 + * 1.95 + * <p>The resulting document will look like this:</p> 1.96 + * 1.97 + * <pre> 1.98 + * <?xml version="1.0" standalone="yes"?> 1.99 + * 1.100 + * <greeting>Hello, world!</greeting> 1.101 + * </pre> 1.102 + * 1.103 + * <p>In fact, there is an even simpler convenience method, 1.104 + * <var>dataElement</var>, designed for writing elements that 1.105 + * contain only character data, so the code to generate the 1.106 + * document could be shortened to</p> 1.107 + * 1.108 + * <pre> 1.109 + * XMLWriter w = new XMLWriter(); 1.110 + * 1.111 + * w.startDocument(); 1.112 + * w.dataElement("greeting", "Hello, world!"); 1.113 + * w.endDocument(); 1.114 + * </pre> 1.115 + * 1.116 + * <h2>Whitespace</h2> 1.117 + * 1.118 + * <p>According to the XML Recommendation, <em>all</em> whitespace 1.119 + * in an XML document is potentially significant to an application, 1.120 + * so this class never adds newlines or indentation. If you 1.121 + * insert three elements in a row, as in</p> 1.122 + * 1.123 + * <pre> 1.124 + * w.dataElement("item", "1"); 1.125 + * w.dataElement("item", "2"); 1.126 + * w.dataElement("item", "3"); 1.127 + * </pre> 1.128 + * 1.129 + * <p>you will end up with</p> 1.130 + * 1.131 + * <pre> 1.132 + * <item>1</item><item>3</item><item>3</item> 1.133 + * </pre> 1.134 + * 1.135 + * <p>You need to invoke one of the <var>characters</var> methods 1.136 + * explicitly to add newlines or indentation. Alternatively, you 1.137 + * can use {@link DataWriter}, which 1.138 + * is derived from this class -- it is optimized for writing 1.139 + * purely data-oriented (or field-oriented) XML, and does automatic 1.140 + * linebreaks and indentation (but does not support mixed content 1.141 + * properly).</p> 1.142 + * 1.143 + * 1.144 + * <h2>Namespace Support</h2> 1.145 + * 1.146 + * <p>The writer contains extensive support for XML Namespaces, so that 1.147 + * a client application does not have to keep track of prefixes and 1.148 + * supply <var>xmlns</var> attributes. By default, the XML writer will 1.149 + * generate Namespace declarations in the form _NS1, _NS2, etc., wherever 1.150 + * they are needed, as in the following example:</p> 1.151 + * 1.152 + * <pre> 1.153 + * w.startDocument(); 1.154 + * w.emptyElement("http://www.foo.com/ns/", "foo"); 1.155 + * w.endDocument(); 1.156 + * </pre> 1.157 + * 1.158 + * <p>The resulting document will look like this:</p> 1.159 + * 1.160 + * <pre> 1.161 + * <?xml version="1.0" standalone="yes"?> 1.162 + * 1.163 + * <_NS1:foo xmlns:_NS1="http://www.foo.com/ns/"/> 1.164 + * </pre> 1.165 + * 1.166 + * <p>In many cases, document authors will prefer to choose their 1.167 + * own prefixes rather than using the (ugly) default names. The 1.168 + * XML writer allows two methods for selecting prefixes:</p> 1.169 + * 1.170 + * <ol> 1.171 + * <li>the qualified name</li> 1.172 + * </ol> 1.173 + * 1.174 + * <p>Whenever the XML writer finds a new Namespace URI, it checks 1.175 + * to see if a qualified (prefixed) name is also available; if so 1.176 + * it attempts to use the name's prefix (as long as the prefix is 1.177 + * not already in use for another Namespace URI).</p> 1.178 + * 1.179 + * <p>The resulting document will look like this:</p> 1.180 + * 1.181 + * <pre> 1.182 + * <?xml version="1.0" standalone="yes"?> 1.183 + * 1.184 + * <foo:foo xmlns:foo="http://www.foo.com/ns/"/> 1.185 + * </pre> 1.186 + * 1.187 + * <p>The default Namespace simply uses an empty string as the prefix:</p> 1.188 + * 1.189 + * <pre> 1.190 + * w.setPrefix("http://www.foo.com/ns/", ""); 1.191 + * w.startDocument(); 1.192 + * w.emptyElement("http://www.foo.com/ns/", "foo"); 1.193 + * w.endDocument(); 1.194 + * </pre> 1.195 + * 1.196 + * <p>The resulting document will look like this:</p> 1.197 + * 1.198 + * <pre> 1.199 + * <?xml version="1.0" standalone="yes"?> 1.200 + * 1.201 + * <foo xmlns="http://www.foo.com/ns/"/> 1.202 + * </pre> 1.203 + * 1.204 + * <p>By default, the XML writer will not declare a Namespace until 1.205 + * it is actually used. Sometimes, this approach will create 1.206 + * a large number of Namespace declarations, as in the following 1.207 + * example:</p> 1.208 + * 1.209 + * <pre> 1.210 + * <xml version="1.0" standalone="yes"?> 1.211 + * 1.212 + * <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> 1.213 + * <rdf:Description about="http://www.foo.com/ids/books/12345"> 1.214 + * <dc:title xmlns:dc="http://www.purl.org/dc/">A Dark Night</dc:title> 1.215 + * <dc:creator xmlns:dc="http://www.purl.org/dc/">Jane Smith</dc:title> 1.216 + * <dc:date xmlns:dc="http://www.purl.org/dc/">2000-09-09</dc:title> 1.217 + * </rdf:Description> 1.218 + * </rdf:RDF> 1.219 + * </pre> 1.220 + * 1.221 + * <p>The "rdf" prefix is declared only once, because the RDF Namespace 1.222 + * is used by the root element and can be inherited by all of its 1.223 + * descendants; the "dc" prefix, on the other hand, is declared three 1.224 + * times, because no higher element uses the Namespace. To solve this 1.225 + * problem, you can instruct the XML writer to predeclare Namespaces 1.226 + * on the root element even if they are not used there:</p> 1.227 + * 1.228 + * <pre> 1.229 + * w.forceNSDecl("http://www.purl.org/dc/"); 1.230 + * </pre> 1.231 + * 1.232 + * <p>Now, the "dc" prefix will be declared on the root element even 1.233 + * though it's not needed there, and can be inherited by its 1.234 + * descendants:</p> 1.235 + * 1.236 + * <pre> 1.237 + * <xml version="1.0" standalone="yes"?> 1.238 + * 1.239 + * <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 1.240 + * xmlns:dc="http://www.purl.org/dc/"> 1.241 + * <rdf:Description about="http://www.foo.com/ids/books/12345"> 1.242 + * <dc:title>A Dark Night</dc:title> 1.243 + * <dc:creator>Jane Smith</dc:title> 1.244 + * <dc:date>2000-09-09</dc:title> 1.245 + * </rdf:Description> 1.246 + * </rdf:RDF> 1.247 + * </pre> 1.248 + * 1.249 + * <p>This approach is also useful for declaring Namespace prefixes 1.250 + * that be used by qualified names appearing in attribute values or 1.251 + * character data.</p> 1.252 + * 1.253 + * @author David Megginson, david@megginson.com 1.254 + * @version 0.2 1.255 + * @since JAXB1.0 1.256 + * @see org.xml.sax.XMLFilter 1.257 + * @see org.xml.sax.ContentHandler 1.258 + */ 1.259 +public class XMLWriter extends XMLFilterImpl 1.260 +{ 1.261 + 1.262 + //////////////////////////////////////////////////////////////////// 1.263 + // Constructors. 1.264 + //////////////////////////////////////////////////////////////////// 1.265 + 1.266 + 1.267 + 1.268 + 1.269 + /** 1.270 + * Create a new XML writer. 1.271 + * 1.272 + * <p>Write to the writer provided.</p> 1.273 + * 1.274 + * @param writer 1.275 + * The output destination, or null to use standard output. 1.276 + * @param encoding 1.277 + * If non-null string is specified, it is written as a part 1.278 + * of the XML declaration. 1.279 + */ 1.280 + public XMLWriter (Writer writer, String encoding, CharacterEscapeHandler _escapeHandler ) 1.281 + { 1.282 + init(writer,encoding); 1.283 + this.escapeHandler = _escapeHandler; 1.284 + } 1.285 + 1.286 + public XMLWriter (Writer writer, String encoding ) { 1.287 + this( writer, encoding, DumbEscapeHandler.theInstance ); 1.288 + } 1.289 + 1.290 + 1.291 + 1.292 + /** 1.293 + * Internal initialization method. 1.294 + * 1.295 + * <p>All of the public constructors invoke this method. 1.296 + * 1.297 + * @param writer The output destination, or null to use 1.298 + * standard output. 1.299 + */ 1.300 + private void init (Writer writer,String encoding) 1.301 + { 1.302 + setOutput(writer,encoding); 1.303 + } 1.304 + 1.305 + 1.306 + 1.307 + //////////////////////////////////////////////////////////////////// 1.308 + // Public methods. 1.309 + //////////////////////////////////////////////////////////////////// 1.310 + 1.311 + 1.312 + /** 1.313 + * Reset the writer. 1.314 + * 1.315 + * <p>This method is especially useful if the writer throws an 1.316 + * exception before it is finished, and you want to reuse the 1.317 + * writer for a new document. It is usually a good idea to 1.318 + * invoke {@link #flush flush} before resetting the writer, 1.319 + * to make sure that no output is lost.</p> 1.320 + * 1.321 + * <p>This method is invoked automatically by the 1.322 + * {@link #startDocument startDocument} method before writing 1.323 + * a new document.</p> 1.324 + * 1.325 + * <p><strong>Note:</strong> this method will <em>not</em> 1.326 + * clear the prefix or URI information in the writer or 1.327 + * the selected output writer.</p> 1.328 + * 1.329 + * @see #flush() 1.330 + */ 1.331 + public void reset () 1.332 + { 1.333 + elementLevel = 0; 1.334 + startTagIsClosed = true; 1.335 + } 1.336 + 1.337 + 1.338 + /** 1.339 + * Flush the output. 1.340 + * 1.341 + * <p>This method flushes the output stream. It is especially useful 1.342 + * when you need to make certain that the entire document has 1.343 + * been written to output but do not want to close the output 1.344 + * stream.</p> 1.345 + * 1.346 + * <p>This method is invoked automatically by the 1.347 + * {@link #endDocument endDocument} method after writing a 1.348 + * document.</p> 1.349 + * 1.350 + * @see #reset() 1.351 + */ 1.352 + public void flush () 1.353 + throws IOException 1.354 + { 1.355 + output.flush(); 1.356 + } 1.357 + 1.358 + 1.359 + /** 1.360 + * Set a new output destination for the document. 1.361 + * 1.362 + * @param writer The output destination, or null to use 1.363 + * standard output. 1.364 + * @see #flush() 1.365 + */ 1.366 + public void setOutput (Writer writer,String _encoding) 1.367 + { 1.368 + if (writer == null) { 1.369 + output = new OutputStreamWriter(System.out); 1.370 + } else { 1.371 + output = writer; 1.372 + } 1.373 + encoding = _encoding; 1.374 + } 1.375 + 1.376 + /** 1.377 + * Set whether the writer should print out the XML declaration 1.378 + * (<?xml version='1.0' ... ?>). 1.379 + * <p> 1.380 + * This option is set to true by default. 1.381 + */ 1.382 + public void setXmlDecl( boolean _writeXmlDecl ) { 1.383 + this.writeXmlDecl = _writeXmlDecl; 1.384 + } 1.385 + 1.386 + /** 1.387 + * Sets the header string. 1.388 + * 1.389 + * This string will be written right after the xml declaration 1.390 + * without any escaping. Useful for generating a boiler-plate 1.391 + * DOCTYPE decl, PIs, and comments. 1.392 + * 1.393 + * @param _header 1.394 + * passing null will work as if the empty string is passed. 1.395 + */ 1.396 + public void setHeader( String _header ) { 1.397 + this.header = _header; 1.398 + } 1.399 + 1.400 + 1.401 + private final HashMap<String,String> locallyDeclaredPrefix = new HashMap<String,String>(); 1.402 + public void startPrefixMapping( String prefix, String uri ) throws SAXException { 1.403 + locallyDeclaredPrefix.put(prefix,uri); 1.404 + } 1.405 + 1.406 + 1.407 + //////////////////////////////////////////////////////////////////// 1.408 + // Methods from org.xml.sax.ContentHandler. 1.409 + //////////////////////////////////////////////////////////////////// 1.410 + 1.411 + /** 1.412 + * Write the XML declaration at the beginning of the document. 1.413 + * 1.414 + * Pass the event on down the filter chain for further processing. 1.415 + * 1.416 + * @exception org.xml.sax.SAXException If there is an error 1.417 + * writing the XML declaration, or if a handler further down 1.418 + * the filter chain raises an exception. 1.419 + * @see org.xml.sax.ContentHandler#startDocument() 1.420 + */ 1.421 + public void startDocument () 1.422 + throws SAXException 1.423 + { 1.424 + try { 1.425 + reset(); 1.426 + 1.427 + if(writeXmlDecl) { 1.428 + String e=""; 1.429 + if(encoding!=null) 1.430 + e = " encoding=\""+encoding+'\"'; 1.431 + 1.432 + writeXmlDecl("<?xml version=\"1.0\""+e +" standalone=\"yes\"?>"); 1.433 + } 1.434 + 1.435 + if(header!=null) 1.436 + write(header); 1.437 + 1.438 + super.startDocument(); 1.439 + } catch( IOException e ) { 1.440 + throw new SAXException(e); 1.441 + } 1.442 + } 1.443 + 1.444 + protected void writeXmlDecl(String decl) throws IOException { 1.445 + write(decl); 1.446 + } 1.447 + 1.448 + 1.449 + /** 1.450 + * Write a newline at the end of the document. 1.451 + * 1.452 + * Pass the event on down the filter chain for further processing. 1.453 + * 1.454 + * @exception org.xml.sax.SAXException If there is an error 1.455 + * writing the newline, or if a handler further down 1.456 + * the filter chain raises an exception. 1.457 + * @see org.xml.sax.ContentHandler#endDocument() 1.458 + */ 1.459 + public void endDocument () 1.460 + throws SAXException 1.461 + { 1.462 + try { 1.463 + super.endDocument(); 1.464 + flush(); 1.465 + } catch( IOException e ) { 1.466 + throw new SAXException(e); 1.467 + } 1.468 + } 1.469 + 1.470 + 1.471 + /** 1.472 + * Write a start tag. 1.473 + * 1.474 + * Pass the event on down the filter chain for further processing. 1.475 + * 1.476 + * @param uri The Namespace URI, or the empty string if none 1.477 + * is available. 1.478 + * @param localName The element's local (unprefixed) name (required). 1.479 + * @param qName The element's qualified (prefixed) name, or the 1.480 + * empty string is none is available. This method will 1.481 + * use the qName as a template for generating a prefix 1.482 + * if necessary, but it is not guaranteed to use the 1.483 + * same qName. 1.484 + * @param atts The element's attribute list (must not be null). 1.485 + * @exception org.xml.sax.SAXException If there is an error 1.486 + * writing the start tag, or if a handler further down 1.487 + * the filter chain raises an exception. 1.488 + * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) 1.489 + */ 1.490 + public void startElement (String uri, String localName, 1.491 + String qName, Attributes atts) 1.492 + throws SAXException 1.493 + { 1.494 + try { 1.495 + if (!startTagIsClosed) { 1.496 + write(">"); 1.497 + } 1.498 + elementLevel++; 1.499 +// nsSupport.pushContext(); 1.500 + 1.501 + write('<'); 1.502 + write(qName); 1.503 + writeAttributes(atts); 1.504 + 1.505 + // declare namespaces specified by the startPrefixMapping methods 1.506 + if(!locallyDeclaredPrefix.isEmpty()) { 1.507 + for (Map.Entry<String,String> e : locallyDeclaredPrefix.entrySet()) { 1.508 + String p = e.getKey(); 1.509 + String u = e.getValue(); 1.510 + if (u == null) { 1.511 + u = ""; 1.512 + } 1.513 + write(' '); 1.514 + if ("".equals(p)) { 1.515 + write("xmlns=\""); 1.516 + } else { 1.517 + write("xmlns:"); 1.518 + write(p); 1.519 + write("=\""); 1.520 + } 1.521 + char ch[] = u.toCharArray(); 1.522 + writeEsc(ch, 0, ch.length, true); 1.523 + write('\"'); 1.524 + } 1.525 + locallyDeclaredPrefix.clear(); // clear the contents 1.526 + } 1.527 + 1.528 +// if (elementLevel == 1) { 1.529 +// forceNSDecls(); 1.530 +// } 1.531 +// writeNSDecls(); 1.532 + super.startElement(uri, localName, qName, atts); 1.533 + startTagIsClosed = false; 1.534 + } catch( IOException e ) { 1.535 + throw new SAXException(e); 1.536 + } 1.537 + } 1.538 + 1.539 + 1.540 + /** 1.541 + * Write an end tag. 1.542 + * 1.543 + * Pass the event on down the filter chain for further processing. 1.544 + * 1.545 + * @param uri The Namespace URI, or the empty string if none 1.546 + * is available. 1.547 + * @param localName The element's local (unprefixed) name (required). 1.548 + * @param qName The element's qualified (prefixed) name, or the 1.549 + * empty string is none is available. This method will 1.550 + * use the qName as a template for generating a prefix 1.551 + * if necessary, but it is not guaranteed to use the 1.552 + * same qName. 1.553 + * @exception org.xml.sax.SAXException If there is an error 1.554 + * writing the end tag, or if a handler further down 1.555 + * the filter chain raises an exception. 1.556 + * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String) 1.557 + */ 1.558 + public void endElement (String uri, String localName, String qName) 1.559 + throws SAXException 1.560 + { 1.561 + try { 1.562 + if (startTagIsClosed) { 1.563 + write("</"); 1.564 + write(qName); 1.565 + write('>'); 1.566 + } else { 1.567 + write("/>"); 1.568 + startTagIsClosed = true; 1.569 + } 1.570 + super.endElement(uri, localName, qName); 1.571 +// nsSupport.popContext(); 1.572 + elementLevel--; 1.573 + } catch( IOException e ) { 1.574 + throw new SAXException(e); 1.575 + } 1.576 + } 1.577 + 1.578 + 1.579 + /** 1.580 + * Write character data. 1.581 + * 1.582 + * Pass the event on down the filter chain for further processing. 1.583 + * 1.584 + * @param ch The array of characters to write. 1.585 + * @param start The starting position in the array. 1.586 + * @param len The number of characters to write. 1.587 + * @exception org.xml.sax.SAXException If there is an error 1.588 + * writing the characters, or if a handler further down 1.589 + * the filter chain raises an exception. 1.590 + * @see org.xml.sax.ContentHandler#characters(char[], int, int) 1.591 + */ 1.592 + public void characters (char ch[], int start, int len) 1.593 + throws SAXException 1.594 + { 1.595 + try { 1.596 + if (!startTagIsClosed) { 1.597 + write('>'); 1.598 + startTagIsClosed = true; 1.599 + } 1.600 + writeEsc(ch, start, len, false); 1.601 + super.characters(ch, start, len); 1.602 + } catch( IOException e ) { 1.603 + throw new SAXException(e); 1.604 + } 1.605 + } 1.606 + 1.607 + 1.608 + /** 1.609 + * Write ignorable whitespace. 1.610 + * 1.611 + * Pass the event on down the filter chain for further processing. 1.612 + * 1.613 + * @param ch The array of characters to write. 1.614 + * @param start The starting position in the array. 1.615 + * @param length The number of characters to write. 1.616 + * @exception org.xml.sax.SAXException If there is an error 1.617 + * writing the whitespace, or if a handler further down 1.618 + * the filter chain raises an exception. 1.619 + * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int) 1.620 + */ 1.621 + public void ignorableWhitespace (char ch[], int start, int length) 1.622 + throws SAXException 1.623 + { 1.624 + try { 1.625 + writeEsc(ch, start, length, false); 1.626 + super.ignorableWhitespace(ch, start, length); 1.627 + } catch( IOException e ) { 1.628 + throw new SAXException(e); 1.629 + } 1.630 + } 1.631 + 1.632 + 1.633 + 1.634 + /** 1.635 + * Write a processing instruction. 1.636 + * 1.637 + * Pass the event on down the filter chain for further processing. 1.638 + * 1.639 + * @param target The PI target. 1.640 + * @param data The PI data. 1.641 + * @exception org.xml.sax.SAXException If there is an error 1.642 + * writing the PI, or if a handler further down 1.643 + * the filter chain raises an exception. 1.644 + * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String) 1.645 + */ 1.646 + public void processingInstruction (String target, String data) 1.647 + throws SAXException 1.648 + { 1.649 + try { 1.650 + if (!startTagIsClosed) { 1.651 + write('>'); 1.652 + startTagIsClosed = true; 1.653 + } 1.654 + write("<?"); 1.655 + write(target); 1.656 + write(' '); 1.657 + write(data); 1.658 + write("?>"); 1.659 + if (elementLevel < 1) { 1.660 + write('\n'); 1.661 + } 1.662 + super.processingInstruction(target, data); 1.663 + } catch( IOException e ) { 1.664 + throw new SAXException(e); 1.665 + } 1.666 + } 1.667 + 1.668 + 1.669 + 1.670 + //////////////////////////////////////////////////////////////////// 1.671 + // Convenience methods. 1.672 + //////////////////////////////////////////////////////////////////// 1.673 + 1.674 + 1.675 + 1.676 + /** 1.677 + * Start a new element without a qname or attributes. 1.678 + * 1.679 + * <p>This method will provide a default empty attribute 1.680 + * list and an empty string for the qualified name. 1.681 + * It invokes {@link 1.682 + * #startElement(String, String, String, Attributes)} 1.683 + * directly.</p> 1.684 + * 1.685 + * @param uri The element's Namespace URI. 1.686 + * @param localName The element's local name. 1.687 + * @exception org.xml.sax.SAXException If there is an error 1.688 + * writing the start tag, or if a handler further down 1.689 + * the filter chain raises an exception. 1.690 + * @see #startElement(String, String, String, Attributes) 1.691 + */ 1.692 + public void startElement (String uri, String localName) 1.693 + throws SAXException 1.694 + { 1.695 + startElement(uri, localName, "", EMPTY_ATTS); 1.696 + } 1.697 + 1.698 + 1.699 + /** 1.700 + * Start a new element without a qname, attributes or a Namespace URI. 1.701 + * 1.702 + * <p>This method will provide an empty string for the 1.703 + * Namespace URI, and empty string for the qualified name, 1.704 + * and a default empty attribute list. It invokes 1.705 + * #startElement(String, String, String, Attributes)} 1.706 + * directly.</p> 1.707 + * 1.708 + * @param localName The element's local name. 1.709 + * @exception org.xml.sax.SAXException If there is an error 1.710 + * writing the start tag, or if a handler further down 1.711 + * the filter chain raises an exception. 1.712 + * @see #startElement(String, String, String, Attributes) 1.713 + */ 1.714 + public void startElement (String localName) 1.715 + throws SAXException 1.716 + { 1.717 + startElement("", localName, "", EMPTY_ATTS); 1.718 + } 1.719 + 1.720 + 1.721 + /** 1.722 + * End an element without a qname. 1.723 + * 1.724 + * <p>This method will supply an empty string for the qName. 1.725 + * It invokes {@link #endElement(String, String, String)} 1.726 + * directly.</p> 1.727 + * 1.728 + * @param uri The element's Namespace URI. 1.729 + * @param localName The element's local name. 1.730 + * @exception org.xml.sax.SAXException If there is an error 1.731 + * writing the end tag, or if a handler further down 1.732 + * the filter chain raises an exception. 1.733 + * @see #endElement(String, String, String) 1.734 + */ 1.735 + public void endElement (String uri, String localName) 1.736 + throws SAXException 1.737 + { 1.738 + endElement(uri, localName, ""); 1.739 + } 1.740 + 1.741 + 1.742 + /** 1.743 + * End an element without a Namespace URI or qname. 1.744 + * 1.745 + * <p>This method will supply an empty string for the qName 1.746 + * and an empty string for the Namespace URI. 1.747 + * It invokes {@link #endElement(String, String, String)} 1.748 + * directly.</p> 1.749 + * 1.750 + * @param localName The element's local name. 1.751 + * @exception org.xml.sax.SAXException If there is an error 1.752 + * writing the end tag, or if a handler further down 1.753 + * the filter chain raises an exception. 1.754 + * @see #endElement(String, String, String) 1.755 + */ 1.756 + public void endElement (String localName) 1.757 + throws SAXException 1.758 + { 1.759 + endElement("", localName, ""); 1.760 + } 1.761 + 1.762 + 1.763 + /** 1.764 + * Write an element with character data content. 1.765 + * 1.766 + * <p>This is a convenience method to write a complete element 1.767 + * with character data content, including the start tag 1.768 + * and end tag.</p> 1.769 + * 1.770 + * <p>This method invokes 1.771 + * {@link #startElement(String, String, String, Attributes)}, 1.772 + * followed by 1.773 + * {@link #characters(String)}, followed by 1.774 + * {@link #endElement(String, String, String)}.</p> 1.775 + * 1.776 + * @param uri The element's Namespace URI. 1.777 + * @param localName The element's local name. 1.778 + * @param qName The element's default qualified name. 1.779 + * @param atts The element's attributes. 1.780 + * @param content The character data content. 1.781 + * @exception org.xml.sax.SAXException If there is an error 1.782 + * writing the empty tag, or if a handler further down 1.783 + * the filter chain raises an exception. 1.784 + * @see #startElement(String, String, String, Attributes) 1.785 + * @see #characters(String) 1.786 + * @see #endElement(String, String, String) 1.787 + */ 1.788 + public void dataElement (String uri, String localName, 1.789 + String qName, Attributes atts, 1.790 + String content) 1.791 + throws SAXException 1.792 + { 1.793 + startElement(uri, localName, qName, atts); 1.794 + characters(content); 1.795 + endElement(uri, localName, qName); 1.796 + } 1.797 + 1.798 + 1.799 + /** 1.800 + * Write an element with character data content but no attributes. 1.801 + * 1.802 + * <p>This is a convenience method to write a complete element 1.803 + * with character data content, including the start tag 1.804 + * and end tag. This method provides an empty string 1.805 + * for the qname and an empty attribute list.</p> 1.806 + * 1.807 + * <p>This method invokes 1.808 + * {@link #startElement(String, String, String, Attributes)}, 1.809 + * followed by 1.810 + * {@link #characters(String)}, followed by 1.811 + * {@link #endElement(String, String, String)}.</p> 1.812 + * 1.813 + * @param uri The element's Namespace URI. 1.814 + * @param localName The element's local name. 1.815 + * @param content The character data content. 1.816 + * @exception org.xml.sax.SAXException If there is an error 1.817 + * writing the empty tag, or if a handler further down 1.818 + * the filter chain raises an exception. 1.819 + * @see #startElement(String, String, String, Attributes) 1.820 + * @see #characters(String) 1.821 + * @see #endElement(String, String, String) 1.822 + */ 1.823 + public void dataElement (String uri, String localName, String content) 1.824 + throws SAXException 1.825 + { 1.826 + dataElement(uri, localName, "", EMPTY_ATTS, content); 1.827 + } 1.828 + 1.829 + 1.830 + /** 1.831 + * Write an element with character data content but no attributes or Namespace URI. 1.832 + * 1.833 + * <p>This is a convenience method to write a complete element 1.834 + * with character data content, including the start tag 1.835 + * and end tag. The method provides an empty string for the 1.836 + * Namespace URI, and empty string for the qualified name, 1.837 + * and an empty attribute list.</p> 1.838 + * 1.839 + * <p>This method invokes 1.840 + * {@link #startElement(String, String, String, Attributes)}, 1.841 + * followed by 1.842 + * {@link #characters(String)}, followed by 1.843 + * {@link #endElement(String, String, String)}.</p> 1.844 + * 1.845 + * @param localName The element's local name. 1.846 + * @param content The character data content. 1.847 + * @exception org.xml.sax.SAXException If there is an error 1.848 + * writing the empty tag, or if a handler further down 1.849 + * the filter chain raises an exception. 1.850 + * @see #startElement(String, String, String, Attributes) 1.851 + * @see #characters(String) 1.852 + * @see #endElement(String, String, String) 1.853 + */ 1.854 + public void dataElement (String localName, String content) 1.855 + throws SAXException 1.856 + { 1.857 + dataElement("", localName, "", EMPTY_ATTS, content); 1.858 + } 1.859 + 1.860 + 1.861 + /** 1.862 + * Write a string of character data, with XML escaping. 1.863 + * 1.864 + * <p>This is a convenience method that takes an XML 1.865 + * String, converts it to a character array, then invokes 1.866 + * {@link #characters(char[], int, int)}.</p> 1.867 + * 1.868 + * @param data The character data. 1.869 + * @exception org.xml.sax.SAXException If there is an error 1.870 + * writing the string, or if a handler further down 1.871 + * the filter chain raises an exception. 1.872 + * @see #characters(char[], int, int) 1.873 + */ 1.874 + public void characters (String data) throws SAXException { 1.875 + try { 1.876 + if (!startTagIsClosed) { 1.877 + write('>'); 1.878 + startTagIsClosed = true; 1.879 + } 1.880 + char ch[] = data.toCharArray(); 1.881 + characters(ch, 0, ch.length); 1.882 + } catch( IOException e ) { 1.883 + throw new SAXException(e); 1.884 + } 1.885 + } 1.886 + 1.887 + 1.888 + 1.889 + //////////////////////////////////////////////////////////////////// 1.890 + // Internal methods. 1.891 + //////////////////////////////////////////////////////////////////// 1.892 + 1.893 + 1.894 + 1.895 + 1.896 + /** 1.897 + * Write a raw character. 1.898 + * 1.899 + * @param c The character to write. 1.900 + */ 1.901 + protected final void write (char c) throws IOException { 1.902 + output.write(c); 1.903 + } 1.904 + 1.905 + 1.906 + /** 1.907 + * Write a raw string. 1.908 + */ 1.909 + protected final void write(String s) throws IOException { 1.910 + output.write(s); 1.911 + } 1.912 + 1.913 + 1.914 + /** 1.915 + * Write out an attribute list, escaping values. 1.916 + * 1.917 + * The names will have prefixes added to them. 1.918 + * 1.919 + * @param atts The attribute list to write. 1.920 + */ 1.921 + private void writeAttributes (Attributes atts) throws IOException { 1.922 + int len = atts.getLength(); 1.923 + for (int i = 0; i < len; i++) { 1.924 + char ch[] = atts.getValue(i).toCharArray(); 1.925 + write(' '); 1.926 + write(atts.getQName(i)); 1.927 + write("=\""); 1.928 + writeEsc(ch, 0, ch.length, true); 1.929 + write('"'); 1.930 + } 1.931 + } 1.932 + 1.933 + 1.934 + /** 1.935 + * Write an array of data characters with escaping. 1.936 + * 1.937 + * @param ch The array of characters. 1.938 + * @param start The starting position. 1.939 + * @param length The number of characters to use. 1.940 + * @param isAttVal true if this is an attribute value literal. 1.941 + */ 1.942 + private void writeEsc (char ch[], int start, 1.943 + int length, boolean isAttVal) 1.944 + throws IOException 1.945 + { 1.946 + escapeHandler.escape(ch, start, length, isAttVal, output); 1.947 + } 1.948 + 1.949 + 1.950 + 1.951 + //////////////////////////////////////////////////////////////////// 1.952 + // Constants. 1.953 + //////////////////////////////////////////////////////////////////// 1.954 + 1.955 + private final Attributes EMPTY_ATTS = new AttributesImpl(); 1.956 + 1.957 + 1.958 + 1.959 + //////////////////////////////////////////////////////////////////// 1.960 + // Internal state. 1.961 + //////////////////////////////////////////////////////////////////// 1.962 + 1.963 + private int elementLevel = 0; 1.964 + private Writer output; 1.965 + private String encoding; 1.966 + private boolean writeXmlDecl = true; 1.967 + /** 1.968 + * This string will be written right after the xml declaration 1.969 + * without any escaping. Useful for generating a boiler-plate DOCTYPE decl 1.970 + * , PIs, and comments. 1.971 + */ 1.972 + private String header=null; 1.973 + 1.974 + private final CharacterEscapeHandler escapeHandler; 1.975 + 1.976 + private boolean startTagIsClosed = true; 1.977 +} 1.978 + 1.979 +// end of XMLWriter.java