Coverage report

  %line %branch
org.apache.commons.jelly.XMLOutput
49% 
81% 

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

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.