View Javadoc
1 /* 2 * $Header: /home/cvs/jakarta-commons-sandbox/jelly/src/java/org/apache/commons/jelly/XMLOutput.java,v 1.6 2002/06/21 03:18:42 jstrachan Exp $ 3 * $Revision: 1.6 $ 4 * $Date: 2002/06/21 03:18:42 $ 5 * 6 * ==================================================================== 7 * 8 * The Apache Software License, Version 1.1 9 * 10 * Copyright (c) 1999-2002 The Apache Software Foundation. All rights 11 * reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in 22 * the documentation and/or other materials provided with the 23 * distribution. 24 * 25 * 3. The end-user documentation included with the redistribution, if 26 * any, must include the following acknowlegement: 27 * "This product includes software developed by the 28 * Apache Software Foundation (http://www.apache.org/)." 29 * Alternately, this acknowlegement may appear in the software itself, 30 * if and wherever such third-party acknowlegements normally appear. 31 * 32 * 4. The names "The Jakarta Project", "Commons", and "Apache Software 33 * Foundation" must not be used to endorse or promote products derived 34 * from this software without prior written permission. For written 35 * permission, please contact apache@apache.org. 36 * 37 * 5. Products derived from this software may not be called "Apache" 38 * nor may "Apache" appear in their names without prior written 39 * permission of the Apache Group. 40 * 41 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 42 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 43 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 44 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 45 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 46 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 47 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 48 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 49 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 50 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 51 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52 * SUCH DAMAGE. 53 * ==================================================================== 54 * 55 * This software consists of voluntary contributions made by many 56 * individuals on behalf of the Apache Software Foundation. For more 57 * information on the Apache Software Foundation, please see 58 * <http://www.apache.org/>;. 59 * 60 * $Id: XMLOutput.java,v 1.6 2002/06/21 03:18:42 jstrachan Exp $ 61 */ 62 63 package org.apache.commons.jelly; 64 65 import java.io.IOException; 66 import java.io.OutputStream; 67 import java.io.UnsupportedEncodingException; 68 import java.io.Writer; 69 70 import org.apache.commons.logging.Log; 71 import org.apache.commons.logging.LogFactory; 72 73 import org.dom4j.io.XMLWriter; 74 75 import org.xml.sax.Attributes; 76 import org.xml.sax.ContentHandler; 77 import org.xml.sax.Locator; 78 import org.xml.sax.SAXException; 79 import org.xml.sax.XMLReader; 80 import org.xml.sax.ext.LexicalHandler; 81 82 /*** <p><code>XMLOutput</code> is used to output XML events 83 * in a SAX-like manner. This also allows pipelining to be done 84 * such as in the <a href="http://xml.apache.org/cocoon/">Cocoon</a> project.</p> 85 * 86 * @author <a href="mailto:jstrachan@apache.org">James Strachan</a> 87 * @version $Revision: 1.6 $ 88 */ 89 90 public class XMLOutput implements ContentHandler, LexicalHandler { 91 92 protected static final String[] LEXICAL_HANDLER_NAMES = 93 { 94 "http://xml.org/sax/properties/lexical-handler", 95 "http://xml.org/sax/handlers/LexicalHandler" }; 96 97 /*** The Log to which logging calls will be made. */ 98 private static final Log log = LogFactory.getLog(XMLOutput.class); 99 100 /*** The SAX ContentHandler that output goes to */ 101 private ContentHandler contentHandler; 102 103 /*** The SAX LexicalHandler that output goes to */ 104 private LexicalHandler lexicalHandler; 105 106 107 public XMLOutput() { 108 } 109 110 public XMLOutput(ContentHandler contentHandler) { 111 this.contentHandler = contentHandler; 112 // often classes will implement LexicalHandler as well 113 if (contentHandler instanceof LexicalHandler) { 114 this.lexicalHandler = (LexicalHandler) contentHandler; 115 } 116 } 117 118 public XMLOutput( 119 ContentHandler contentHandler, 120 LexicalHandler lexicalHandler) { 121 this.contentHandler = contentHandler; 122 this.lexicalHandler = lexicalHandler; 123 } 124 125 public String toString() { 126 return super.toString() 127 + "[contentHandler=" 128 + contentHandler 129 + ";lexicalHandler=" 130 + lexicalHandler 131 + "]"; 132 } 133 134 /*** 135 * Provides a useful hook that implementations can use to close the 136 * underlying OutputStream or Writer 137 */ 138 public void close() throws IOException { 139 } 140 141 public void flush() throws IOException { 142 ((XMLWriter)contentHandler).flush(); 143 } 144 145 // Static helper methods 146 //------------------------------------------------------------------------- 147 148 /*** 149 * Creates an XMLOutput from an existing SAX XMLReader 150 */ 151 public static XMLOutput createXMLOutput(XMLReader xmlReader) { 152 XMLOutput output = new XMLOutput(xmlReader.getContentHandler()); 153 154 // isn't it lovely what we've got to do to find the LexicalHandler... ;-) 155 for (int i = 0; i < LEXICAL_HANDLER_NAMES.length; i++) { 156 try { 157 Object value = xmlReader.getProperty(LEXICAL_HANDLER_NAMES[i]); 158 if (value instanceof LexicalHandler) { 159 output.setLexicalHandler((LexicalHandler) value); 160 break; 161 } 162 } 163 catch (Exception e) { 164 // ignore any unsupported-operation exceptions 165 } 166 } 167 return output; 168 } 169 170 /*** 171 * Creates a text based XMLOutput which converts all XML events into 172 * text and writes to the underlying Writer. 173 */ 174 public static XMLOutput createXMLOutput(Writer writer) { 175 XMLWriter xmlWriter = new XMLWriter(writer); 176 return createXMLOutput(xmlWriter); 177 } 178 179 /*** 180 * Creates a text based XMLOutput which converts all XML events into 181 * text and writes to the underlying Writer. 182 * 183 * @param writer is the writer to output to 184 * @param escapeText is whether or not text output will be escaped. This must be true 185 * if the underlying output is XML or could be false if the underlying output is textual. 186 */ 187 public static XMLOutput createXMLOutput(Writer writer, boolean escapeText) throws UnsupportedEncodingException { 188 XMLWriter xmlWriter = new XMLWriter(writer); 189 xmlWriter.setEscapeText(escapeText); 190 return createXMLOutput(xmlWriter); 191 } 192 193 /*** 194 * Creates a text based XMLOutput which converts all XML events into 195 * text and writes to the underlying OutputStream. 196 */ 197 public static XMLOutput createXMLOutput(OutputStream out) throws UnsupportedEncodingException { 198 XMLWriter xmlWriter = new XMLWriter(out); 199 return createXMLOutput(xmlWriter); 200 } 201 202 /*** 203 * Creates a text based XMLOutput which converts all XML events into 204 * text and writes to the underlying OutputStream. 205 * 206 * @param out is the output stream to write 207 * @param escapeText is whether or not text output will be escaped. This must be true 208 * if the underlying output is XML or could be false if the underlying output is textual. 209 */ 210 public static XMLOutput createXMLOutput(OutputStream out, boolean escapeText) throws UnsupportedEncodingException { 211 XMLWriter xmlWriter = new XMLWriter(out); 212 xmlWriter.setEscapeText(escapeText); 213 return createXMLOutput(xmlWriter); 214 } 215 216 // Extra helper methods provided for tag authors 217 //------------------------------------------------------------------------- 218 219 /*** 220 * Outputs the given String as a piece of valid text in the 221 * XML event stream. 222 * Any special XML characters should be properly escaped. 223 */ 224 public void write(String text) throws SAXException { 225 char[] ch = text.toCharArray(); 226 characters(ch, 0, ch.length); 227 } 228 229 /*** 230 * Outputs the given String as a piece of CDATA in the 231 * XML event stream. 232 */ 233 public void writeCDATA(String text) throws SAXException { 234 startCDATA(); 235 char[] ch = text.toCharArray(); 236 characters(ch, 0, ch.length); 237 endCDATA(); 238 } 239 240 /*** 241 * Outputs a comment to the XML stream 242 */ 243 public void writeComment(String text) throws SAXException { 244 char[] ch = text.toCharArray(); 245 comment(ch, 0, ch.length); 246 } 247 248 // ContentHandler interface 249 //------------------------------------------------------------------------- 250 251 /*** 252 * Receive an object for locating the origin of SAX document events. 253 * 254 * <p>SAX parsers are strongly encouraged (though not absolutely 255 * required) to supply a locator: if it does so, it must supply 256 * the locator to the application by invoking this method before 257 * invoking any of the other methods in the ContentHandler 258 * interface.</p> 259 * 260 * <p>The locator allows the application to determine the end 261 * position of any document-related event, even if the parser is 262 * not reporting an error. Typically, the application will 263 * use this information for reporting its own errors (such as 264 * character content that does not match an application's 265 * business rules). The information returned by the locator 266 * is probably not sufficient for use with a search engine.</p> 267 * 268 * <p>Note that the locator will return correct information only 269 * during the invocation of the events in this interface. The 270 * application should not attempt to use it at any other time.</p> 271 * 272 * @param locator An object that can return the location of 273 * any SAX document event. 274 * @see org.xml.sax.Locator 275 */ 276 public void setDocumentLocator(Locator locator) { 277 contentHandler.setDocumentLocator(locator); 278 } 279 280 /*** 281 * Receive notification of the beginning of a document. 282 * 283 * <p>The SAX parser will invoke this method only once, before any 284 * other event callbacks (except for {@link #setDocumentLocator 285 * setDocumentLocator}).</p> 286 * 287 * @exception org.xml.sax.SAXException Any SAX exception, possibly 288 * wrapping another exception. 289 * @see #endDocument 290 */ 291 public void startDocument() throws SAXException { 292 contentHandler.startDocument(); 293 } 294 295 /*** 296 * Receive notification of the end of a document. 297 * 298 * <p>The SAX parser will invoke this method only once, and it will 299 * be the last method invoked during the parse. The parser shall 300 * not invoke this method until it has either abandoned parsing 301 * (because of an unrecoverable error) or reached the end of 302 * input.</p> 303 * 304 * @exception org.xml.sax.SAXException Any SAX exception, possibly 305 * wrapping another exception. 306 * @see #startDocument 307 */ 308 public void endDocument() throws SAXException { 309 contentHandler.endDocument(); 310 } 311 312 /*** 313 * Begin the scope of a prefix-URI Namespace mapping. 314 * 315 * <p>The information from this event is not necessary for 316 * normal Namespace processing: the SAX XML reader will 317 * automatically replace prefixes for element and attribute 318 * names when the <code>http://xml.org/sax/features/namespaces<;/code> 319 * feature is <var>true</var> (the default).</p> 320 * 321 * <p>There are cases, however, when applications need to 322 * use prefixes in character data or in attribute values, 323 * where they cannot safely be expanded automatically; the 324 * start/endPrefixMapping event supplies the information 325 * to the application to expand prefixes in those contexts 326 * itself, if necessary.</p> 327 * 328 * <p>Note that start/endPrefixMapping events are not 329 * guaranteed to be properly nested relative to each other: 330 * all startPrefixMapping events will occur immediately before the 331 * corresponding {@link #startElement startElement} event, 332 * and all {@link #endPrefixMapping endPrefixMapping} 333 * events will occur immediately after the corresponding 334 * {@link #endElement endElement} event, 335 * but their order is not otherwise 336 * guaranteed.</p> 337 * 338 * <p>There should never be start/endPrefixMapping events for the 339 * "xml" prefix, since it is predeclared and immutable.</p> 340 * 341 * @param prefix The Namespace prefix being declared. 342 * An empty string is used for the default element namespace, 343 * which has no prefix. 344 * @param uri The Namespace URI the prefix is mapped to. 345 * @exception org.xml.sax.SAXException The client may throw 346 * an exception during processing. 347 * @see #endPrefixMapping 348 * @see #startElement 349 */ 350 public void startPrefixMapping(String prefix, String uri) throws SAXException { 351 contentHandler.startPrefixMapping(prefix, uri); 352 } 353 354 /*** 355 * End the scope of a prefix-URI mapping. 356 * 357 * <p>See {@link #startPrefixMapping startPrefixMapping} for 358 * details. These events will always occur immediately after the 359 * corresponding {@link #endElement endElement} event, but the order of 360 * {@link #endPrefixMapping endPrefixMapping} events is not otherwise 361 * guaranteed.</p> 362 * 363 * @param prefix The prefix that was being mapped. 364 * This is the empty string when a default mapping scope ends. 365 * @exception org.xml.sax.SAXException The client may throw 366 * an exception during processing. 367 * @see #startPrefixMapping 368 * @see #endElement 369 */ 370 public void endPrefixMapping(String prefix) throws SAXException { 371 contentHandler.endPrefixMapping(prefix); 372 } 373 374 /*** 375 * Receive notification of the beginning of an element. 376 * 377 * <p>The Parser will invoke this method at the beginning of every 378 * element in the XML document; there will be a corresponding 379 * {@link #endElement endElement} event for every startElement event 380 * (even when the element is empty). All of the element's content will be 381 * reported, in order, before the corresponding endElement 382 * event.</p> 383 * 384 * <p>This event allows up to three name components for each 385 * element:</p> 386 * 387 * <ol> 388 * <li>the Namespace URI;</li> 389 * <li>the local name; and</li> 390 * <li>the qualified (prefixed) name.</li> 391 * </ol> 392 * 393 * <p>Any or all of these may be provided, depending on the 394 * values of the <var>http://xml.org/sax/features/namespaces<;/var> 395 * and the <var>http://xml.org/sax/features/namespace-prefixes</var> 396 * properties:</p> 397 * 398 * <ul> 399 * <li>the Namespace URI and local name are required when 400 * the namespaces property is <var>true</var> (the default), and are 401 * optional when the namespaces property is <var>false</var> (if one is 402 * specified, both must be);</li> 403 * <li>the qualified name is required when the namespace-prefixes property 404 * is <var>true</var>, and is optional when the namespace-prefixes property 405 * is <var>false</var> (the default).</li> 406 * </ul> 407 * 408 * <p>Note that the attribute list provided will contain only 409 * attributes with explicit values (specified or defaulted): 410 * #IMPLIED attributes will be omitted. The attribute list 411 * will contain attributes used for Namespace declarations 412 * (xmlns* attributes) only if the 413 * <code>http://xml.org/sax/features/namespace-prefixes</code> 414 * property is true (it is false by default, and support for a 415 * true value is optional).</p> 416 * 417 * <p>Like {@link #characters characters()}, attribute values may have 418 * characters that need more than one <code>char</code> value. </p> 419 * 420 * @param uri The Namespace URI, or the empty string if the 421 * element has no Namespace URI or if Namespace 422 * processing is not being performed. 423 * @param localName The local name (without prefix), or the 424 * empty string if Namespace processing is not being 425 * performed. 426 * @param qName The qualified name (with prefix), or the 427 * empty string if qualified names are not available. 428 * @param atts The attributes attached to the element. If 429 * there are no attributes, it shall be an empty 430 * Attributes object. 431 * @exception org.xml.sax.SAXException Any SAX exception, possibly 432 * wrapping another exception. 433 * @see #endElement 434 * @see org.xml.sax.Attributes 435 */ 436 public void startElement( 437 String uri, 438 String localName, 439 String qName, 440 Attributes atts) 441 throws SAXException { 442 contentHandler.startElement(uri, localName, qName, atts); 443 } 444 445 /*** 446 * Receive notification of the end of an element. 447 * 448 * <p>The SAX parser will invoke this method at the end of every 449 * element in the XML document; there will be a corresponding 450 * {@link #startElement startElement} event for every endElement 451 * event (even when the element is empty).</p> 452 * 453 * <p>For information on the names, see startElement.</p> 454 * 455 * @param uri The Namespace URI, or the empty string if the 456 * element has no Namespace URI or if Namespace 457 * processing is not being performed. 458 * @param localName The local name (without prefix), or the 459 * empty string if Namespace processing is not being 460 * performed. 461 * @param qName The qualified XML 1.0 name (with prefix), or the 462 * empty string if qualified names are not available. 463 * @exception org.xml.sax.SAXException Any SAX exception, possibly 464 * wrapping another exception. 465 */ 466 public void endElement(String uri, String localName, String qName) 467 throws SAXException { 468 contentHandler.endElement(uri, localName, qName); 469 } 470 471 /*** 472 * Receive notification of character data. 473 * 474 * <p>The Parser will call this method to report each chunk of 475 * character data. SAX parsers may return all contiguous character 476 * data in a single chunk, or they may split it into several 477 * chunks; however, all of the characters in any single event 478 * must come from the same external entity so that the Locator 479 * provides useful information.</p> 480 * 481 * <p>The application must not attempt to read from the array 482 * outside of the specified range.</p> 483 * 484 * <p>Individual characters may consist of more than one Java 485 * <code>char</code> value. There are two important cases where this 486 * happens, because characters can't be represented in just sixteen bits. 487 * In one case, characters are represented in a <em>Surrogate Pair</em>, 488 * using two special Unicode values. Such characters are in the so-called 489 * "Astral Planes", with a code point above U+FFFF. A second case involves 490 * composite characters, such as a base character combining with one or 491 * more accent characters. </p> 492 * 493 * <p> Your code should not assume that algorithms using 494 * <code>char</code>-at-a-time idioms will be working in character 495 * units; in some cases they will split characters. This is relevant 496 * wherever XML permits arbitrary characters, such as attribute values, 497 * processing instruction data, and comments as well as in data reported 498 * from this method. It's also generally relevant whenever Java code 499 * manipulates internationalized text; the issue isn't unique to XML.</p> 500 * 501 * <p>Note that some parsers will report whitespace in element 502 * content using the {@link #ignorableWhitespace ignorableWhitespace} 503 * method rather than this one (validating parsers <em>must</em> 504 * do so).</p> 505 * 506 * @param ch The characters from the XML document. 507 * @param start The start position in the array. 508 * @param length The number of characters to read from the array. 509 * @exception org.xml.sax.SAXException Any SAX exception, possibly 510 * wrapping another exception. 511 * @see #ignorableWhitespace 512 * @see org.xml.sax.Locator 513 */ 514 public void characters(char ch[], int start, int length) throws SAXException { 515 contentHandler.characters(ch, start, length); 516 } 517 518 /*** 519 * Receive notification of ignorable whitespace in element content. 520 * 521 * <p>Validating Parsers must use this method to report each chunk 522 * of whitespace in element content (see the W3C XML 1.0 recommendation, 523 * section 2.10): non-validating parsers may also use this method 524 * if they are capable of parsing and using content models.</p> 525 * 526 * <p>SAX parsers may return all contiguous whitespace in a single 527 * chunk, or they may split it into several chunks; however, all of 528 * the characters in any single event must come from the same 529 * external entity, so that the Locator provides useful 530 * information.</p> 531 * 532 * <p>The application must not attempt to read from the array 533 * outside of the specified range.</p> 534 * 535 * @param ch The characters from the XML document. 536 * @param start The start position in the array. 537 * @param length The number of characters to read from the array. 538 * @exception org.xml.sax.SAXException Any SAX exception, possibly 539 * wrapping another exception. 540 * @see #characters 541 */ 542 public void ignorableWhitespace(char ch[], int start, int length) 543 throws SAXException { 544 contentHandler.ignorableWhitespace(ch, start, length); 545 } 546 547 /*** 548 * Receive notification of a processing instruction. 549 * 550 * <p>The Parser will invoke this method once for each processing 551 * instruction found: note that processing instructions may occur 552 * before or after the main document element.</p> 553 * 554 * <p>A SAX parser must never report an XML declaration (XML 1.0, 555 * section 2.8) or a text declaration (XML 1.0, section 4.3.1) 556 * using this method.</p> 557 * 558 * <p>Like {@link #characters characters()}, processing instruction 559 * data may have characters that need more than one <code>char</code> 560 * value. </p> 561 * 562 * @param target The processing instruction target. 563 * @param data The processing instruction data, or null if 564 * none was supplied. The data does not include any 565 * whitespace separating it from the target. 566 * @exception org.xml.sax.SAXException Any SAX exception, possibly 567 * wrapping another exception. 568 */ 569 public void processingInstruction(String target, String data) 570 throws SAXException { 571 contentHandler.processingInstruction(target, data); 572 } 573 574 /*** 575 * Receive notification of a skipped entity. 576 * This is not called for entity references within markup constructs 577 * such as element start tags or markup declarations. (The XML 578 * recommendation requires reporting skipped external entities. 579 * SAX also reports internal entity expansion/non-expansion, except 580 * within markup constructs.) 581 * 582 * <p>The Parser will invoke this method each time the entity is 583 * skipped. Non-validating processors may skip entities if they 584 * have not seen the declarations (because, for example, the 585 * entity was declared in an external DTD subset). All processors 586 * may skip external entities, depending on the values of the 587 * <code>http://xml.org/sax/features/external-general-entities</code> 588 * and the 589 * <code>http://xml.org/sax/features/external-parameter-entities</code> 590 * properties.</p> 591 * 592 * @param name The name of the skipped entity. If it is a 593 * parameter entity, the name will begin with '%', and if 594 * it is the external DTD subset, it will be the string 595 * "[dtd]". 596 * @exception org.xml.sax.SAXException Any SAX exception, possibly 597 * wrapping another exception. 598 */ 599 public void skippedEntity(String name) throws SAXException { 600 contentHandler.skippedEntity(name); 601 } 602 603 604 // Lexical Handler interface 605 //------------------------------------------------------------------------- 606 607 /*** 608 * Report the start of DTD declarations, if any. 609 * 610 * <p>This method is intended to report the beginning of the 611 * DOCTYPE declaration; if the document has no DOCTYPE declaration, 612 * this method will not be invoked.</p> 613 * 614 * <p>All declarations reported through 615 * {@link org.xml.sax.DTDHandler DTDHandler} or 616 * {@link org.xml.sax.ext.DeclHandler DeclHandler} events must appear 617 * between the startDTD and {@link #endDTD endDTD} events. 618 * Declarations are assumed to belong to the internal DTD subset 619 * unless they appear between {@link #startEntity startEntity} 620 * and {@link #endEntity endEntity} events. Comments and 621 * processing instructions from the DTD should also be reported 622 * between the startDTD and endDTD events, in their original 623 * order of (logical) occurrence; they are not required to 624 * appear in their correct locations relative to DTDHandler 625 * or DeclHandler events, however.</p> 626 * 627 * <p>Note that the start/endDTD events will appear within 628 * the start/endDocument events from ContentHandler and 629 * before the first 630 * {@link org.xml.sax.ContentHandler#startElement startElement} 631 * event.</p> 632 * 633 * @param name The document type name. 634 * @param publicId The declared public identifier for the 635 * external DTD subset, or null if none was declared. 636 * @param systemId The declared system identifier for the 637 * external DTD subset, or null if none was declared. 638 * (Note that this is not resolved against the document 639 * base URI.) 640 * @exception SAXException The application may raise an 641 * exception. 642 * @see #endDTD 643 * @see #startEntity 644 */ 645 public void startDTD(String name, String publicId, String systemId) 646 throws SAXException { 647 if (lexicalHandler != null) { 648 lexicalHandler.startDTD(name, publicId, systemId); 649 } 650 } 651 652 /*** 653 * Report the end of DTD declarations. 654 * 655 * <p>This method is intended to report the end of the 656 * DOCTYPE declaration; if the document has no DOCTYPE declaration, 657 * this method will not be invoked.</p> 658 * 659 * @exception SAXException The application may raise an exception. 660 * @see #startDTD 661 */ 662 public void endDTD() throws SAXException { 663 if (lexicalHandler != null) { 664 lexicalHandler.endDTD(); 665 } 666 } 667 668 /*** 669 * Report the beginning of some internal and external XML entities. 670 * 671 * <p>The reporting of parameter entities (including 672 * the external DTD subset) is optional, and SAX2 drivers that 673 * report LexicalHandler events may not implement it; you can use the 674 * <code 675 * >http://xml.org/sax/features/lexical-handler/parameter-entities</code> 676 * feature to query or control the reporting of parameter entities.</p> 677 * 678 * <p>General entities are reported with their regular names, 679 * parameter entities have '%' prepended to their names, and 680 * the external DTD subset has the pseudo-entity name "[dtd]".</p> 681 * 682 * <p>When a SAX2 driver is providing these events, all other 683 * events must be properly nested within start/end entity 684 * events. There is no additional requirement that events from 685 * {@link org.xml.sax.ext.DeclHandler DeclHandler} or 686 * {@link org.xml.sax.DTDHandler DTDHandler} be properly ordered.</p> 687 * 688 * <p>Note that skipped entities will be reported through the 689 * {@link org.xml.sax.ContentHandler#skippedEntity skippedEntity} 690 * event, which is part of the ContentHandler interface.</p> 691 * 692 * <p>Because of the streaming event model that SAX uses, some 693 * entity boundaries cannot be reported under any 694 * circumstances:</p> 695 * 696 * <ul> 697 * <li>general entities within attribute values</li> 698 * <li>parameter entities within declarations</li> 699 * </ul> 700 * 701 * <p>These will be silently expanded, with no indication of where 702 * the original entity boundaries were.</p> 703 * 704 * <p>Note also that the boundaries of character references (which 705 * are not really entities anyway) are not reported.</p> 706 * 707 * <p>All start/endEntity events must be properly nested. 708 * 709 * @param name The name of the entity. If it is a parameter 710 * entity, the name will begin with '%', and if it is the 711 * external DTD subset, it will be "[dtd]". 712 * @exception SAXException The application may raise an exception. 713 * @see #endEntity 714 * @see org.xml.sax.ext.DeclHandler#internalEntityDecl 715 * @see org.xml.sax.ext.DeclHandler#externalEntityDecl 716 */ 717 public void startEntity(String name) throws SAXException { 718 if (lexicalHandler != null) { 719 lexicalHandler.startEntity(name); 720 } 721 } 722 723 /*** 724 * Report the end of an entity. 725 * 726 * @param name The name of the entity that is ending. 727 * @exception SAXException The application may raise an exception. 728 * @see #startEntity 729 */ 730 public void endEntity(String name) throws SAXException { 731 if (lexicalHandler != null) { 732 lexicalHandler.endEntity(name); 733 } 734 } 735 736 /*** 737 * Report the start of a CDATA section. 738 * 739 * <p>The contents of the CDATA section will be reported through 740 * the regular {@link org.xml.sax.ContentHandler#characters 741 * characters} event; this event is intended only to report 742 * the boundary.</p> 743 * 744 * @exception SAXException The application may raise an exception. 745 * @see #endCDATA 746 */ 747 public void startCDATA() throws SAXException { 748 if (lexicalHandler != null) { 749 lexicalHandler.startCDATA(); 750 } 751 } 752 753 /*** 754 * Report the end of a CDATA section. 755 * 756 * @exception SAXException The application may raise an exception. 757 * @see #startCDATA 758 */ 759 public void endCDATA() throws SAXException { 760 if (lexicalHandler != null) { 761 lexicalHandler.endCDATA(); 762 } 763 } 764 765 /*** 766 * Report an XML comment anywhere in the document. 767 * 768 * <p>This callback will be used for comments inside or outside the 769 * document element, including comments in the external DTD 770 * subset (if read). Comments in the DTD must be properly 771 * nested inside start/endDTD and start/endEntity events (if 772 * used).</p> 773 * 774 * @param ch An array holding the characters in the comment. 775 * @param start The starting position in the array. 776 * @param length The number of characters to use from the array. 777 * @exception SAXException The application may raise an exception. 778 */ 779 public void comment(char ch[], int start, int length) throws SAXException { 780 if (lexicalHandler != null) { 781 lexicalHandler.comment(ch, start, length); 782 } 783 } 784 785 // Properties 786 //------------------------------------------------------------------------- 787 /*** 788 * @return the SAX ContentHandler to use to pipe SAX events into 789 */ 790 public ContentHandler getContentHandler() { 791 return contentHandler; 792 } 793 794 /*** 795 * Sets the SAX ContentHandler to pipe SAX events into 796 * 797 * @param contentHandler is the new ContentHandler to use. 798 * This value cannot be null. 799 */ 800 public void setContentHandler(ContentHandler contentHandler) { 801 if (contentHandler == null) { 802 throw new NullPointerException("ContentHandler cannot be null!"); 803 } 804 this.contentHandler = contentHandler; 805 } 806 807 /*** 808 * @return the SAX LexicalHandler to use to pipe SAX events into 809 */ 810 public LexicalHandler getLexicalHandler() { 811 return lexicalHandler; 812 } 813 814 /*** 815 * Sets the SAX LexicalHandler to pipe SAX events into 816 * 817 * @param lexicalHandler is the new LexicalHandler to use. 818 * This value can be null. 819 */ 820 public void setLexicalHandler(LexicalHandler lexicalHandler) { 821 this.lexicalHandler = lexicalHandler; 822 } 823 824 // Implementation methods 825 //------------------------------------------------------------------------- 826 /*** 827 * Factory method to create a new XMLOutput from an XMLWriter 828 */ 829 protected static XMLOutput createXMLOutput(final XMLWriter xmlWriter) { 830 XMLOutput answer = new XMLOutput() { 831 public void close() throws IOException { 832 xmlWriter.close(); 833 } 834 }; 835 answer.setContentHandler(xmlWriter); 836 answer.setLexicalHandler(xmlWriter); 837 return answer; 838 } 839 840 }

This page was automatically generated by Maven