Home | History | Annotate | Download | only in transformer
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one
      3  * or more contributor license agreements. See the NOTICE file
      4  * distributed with this work for additional information
      5  * regarding copyright ownership. The ASF licenses this file
      6  * to you under the Apache License, Version 2.0 (the  "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  */
     18 /*
     19  * $Id: TransformerHandlerImpl.java 468645 2006-10-28 06:57:24Z minchau $
     20  */
     21 package org.apache.xalan.transformer;
     22 
     23 import java.io.IOException;
     24 
     25 import javax.xml.transform.Result;
     26 import javax.xml.transform.Transformer;
     27 import javax.xml.transform.sax.TransformerHandler;
     28 
     29 import org.apache.xalan.res.XSLMessages;
     30 import org.apache.xalan.res.XSLTErrorResources;
     31 import org.apache.xml.dtm.DTM;
     32 import org.apache.xml.dtm.DTMManager;
     33 import org.apache.xml.dtm.ref.IncrementalSAXSource_Filter;
     34 import org.apache.xml.dtm.ref.sax2dtm.SAX2DTM;
     35 import org.apache.xpath.XPathContext;
     36 
     37 import org.xml.sax.Attributes;
     38 import org.xml.sax.ContentHandler;
     39 import org.xml.sax.DTDHandler;
     40 import org.xml.sax.EntityResolver;
     41 import org.xml.sax.ErrorHandler;
     42 import org.xml.sax.InputSource;
     43 import org.xml.sax.Locator;
     44 import org.xml.sax.SAXException;
     45 import org.xml.sax.SAXParseException;
     46 import org.xml.sax.ext.DeclHandler;
     47 import org.xml.sax.ext.LexicalHandler;
     48 import org.apache.xml.serializer.SerializationHandler;
     49 
     50 
     51 /**
     52  * A TransformerHandler
     53  * listens for SAX ContentHandler parse events and transforms
     54  * them to a Result.
     55  */
     56 public class TransformerHandlerImpl
     57         implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler,
     58                    LexicalHandler, TransformerHandler, DeclHandler
     59 {
     60     /**
     61      * The flag for the setting of the optimize feature;
     62      */
     63     private final boolean m_optimizer;
     64 
     65     /**
     66      * The flag for the setting of the incremental feature;
     67      */
     68     private final boolean m_incremental;
     69 
     70     /**
     71      * The flag for the setting of the source_location feature;
     72      */
     73     private final boolean m_source_location;
     74 
     75   private boolean m_insideParse = false;
     76 
     77   ////////////////////////////////////////////////////////////////////
     78   // Constructors.
     79   ////////////////////////////////////////////////////////////////////
     80 
     81   /**
     82    * Construct a TransformerHandlerImpl.
     83    *
     84    * @param transformer Non-null reference to the Xalan transformer impl.
     85    * @param doFragment True if the result should be a document fragement.
     86    * @param baseSystemID  The system ID to use as the base for relative URLs.
     87    */
     88   public TransformerHandlerImpl(TransformerImpl transformer,
     89                                 boolean doFragment, String baseSystemID)
     90   {
     91 
     92     super();
     93 
     94     m_transformer = transformer;
     95     m_baseSystemID = baseSystemID;
     96 
     97     XPathContext xctxt = transformer.getXPathContext();
     98     DTM dtm = xctxt.getDTM(null, true, transformer, true, true);
     99 
    100     m_dtm = dtm;
    101     dtm.setDocumentBaseURI(baseSystemID);
    102 
    103     m_contentHandler = dtm.getContentHandler();
    104     m_dtdHandler = dtm.getDTDHandler();
    105     m_entityResolver = dtm.getEntityResolver();
    106     m_errorHandler = dtm.getErrorHandler();
    107     m_lexicalHandler = dtm.getLexicalHandler();
    108     m_incremental = transformer.getIncremental();
    109     m_optimizer = transformer.getOptimize();
    110     m_source_location = transformer.getSource_location();
    111   }
    112 
    113   /**
    114    * Do what needs to be done to shut down the CoRoutine management.
    115    */
    116   protected void clearCoRoutine()
    117   {
    118     clearCoRoutine(null);
    119   }
    120 
    121   /**
    122    * Do what needs to be done to shut down the CoRoutine management.
    123    */
    124   protected void clearCoRoutine(SAXException ex)
    125   {
    126     if(null != ex)
    127       m_transformer.setExceptionThrown(ex);
    128 
    129     if(m_dtm instanceof SAX2DTM)
    130     {
    131       if(DEBUG)
    132         System.err.println("In clearCoRoutine...");
    133       try
    134       {
    135         SAX2DTM sax2dtm = ((SAX2DTM)m_dtm);
    136         if(null != m_contentHandler
    137            && m_contentHandler instanceof IncrementalSAXSource_Filter)
    138         {
    139           IncrementalSAXSource_Filter sp =
    140             (IncrementalSAXSource_Filter)m_contentHandler;
    141           // This should now be all that's needed.
    142           sp.deliverMoreNodes(false);
    143         }
    144 
    145         sax2dtm.clearCoRoutine(true);
    146         m_contentHandler = null;
    147         m_dtdHandler = null;
    148         m_entityResolver = null;
    149         m_errorHandler = null;
    150         m_lexicalHandler = null;
    151       }
    152       catch(Throwable throwable)
    153       {
    154         throwable.printStackTrace();
    155       }
    156 
    157       if(DEBUG)
    158         System.err.println("...exiting clearCoRoutine");
    159     }
    160   }
    161 
    162   ////////////////////////////////////////////////////////////////////
    163   // Implementation of javax.xml.transform.sax.TransformerHandler.
    164   ////////////////////////////////////////////////////////////////////
    165 
    166   /**
    167    * Enables the user of the TransformerHandler to set the
    168    * to set the Result for the transformation.
    169    *
    170    * @param result A Result instance, should not be null.
    171    *
    172    * @throws IllegalArgumentException if result is invalid for some reason.
    173    */
    174   public void setResult(Result result) throws IllegalArgumentException
    175   {
    176 
    177     if (null == result)
    178       throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_RESULT_NULL, null)); //"result should not be null");
    179 
    180     try
    181     {
    182 //      ContentHandler handler =
    183 //        m_transformer.createResultContentHandler(result);
    184 //      m_transformer.setContentHandler(handler);
    185         SerializationHandler xoh =
    186             m_transformer.createSerializationHandler(result);
    187         m_transformer.setSerializationHandler(xoh);
    188     }
    189     catch (javax.xml.transform.TransformerException te)
    190     {
    191       throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_RESULT_COULD_NOT_BE_SET, null)); //"result could not be set");
    192     }
    193 
    194     m_result = result;
    195   }
    196 
    197   /**
    198    * Set the base ID (URI or system ID) from where relative
    199    * URLs will be resolved.
    200    * @param systemID Base URI for the source tree.
    201    */
    202   public void setSystemId(String systemID)
    203   {
    204     m_baseSystemID = systemID;
    205     m_dtm.setDocumentBaseURI(systemID);
    206   }
    207 
    208   /**
    209    * Get the base ID (URI or system ID) from where relative
    210    * URLs will be resolved.
    211    * @return The systemID that was set with {@link #setSystemId}.
    212    */
    213   public String getSystemId()
    214   {
    215     return m_baseSystemID;
    216   }
    217 
    218   /**
    219    * Get the Transformer associated with this handler, which
    220    * is needed in order to set parameters and output properties.
    221    *
    222    * @return The Transformer associated with this handler
    223    */
    224   public Transformer getTransformer()
    225   {
    226     return m_transformer;
    227   }
    228 
    229   ////////////////////////////////////////////////////////////////////
    230   // Implementation of org.xml.sax.EntityResolver.
    231   ////////////////////////////////////////////////////////////////////
    232 
    233   /**
    234    * Filter an external entity resolution.
    235    *
    236    * @param publicId The entity's public identifier, or null.
    237    * @param systemId The entity's system identifier.
    238    * @return A new InputSource or null for the default.
    239    *
    240    * @throws IOException
    241    * @throws SAXException The client may throw
    242    *            an exception during processing.
    243    * @throws java.io.IOException The client may throw an
    244    *            I/O-related exception while obtaining the
    245    *            new InputSource.
    246    * @see org.xml.sax.EntityResolver#resolveEntity
    247    */
    248   public InputSource resolveEntity(String publicId, String systemId)
    249           throws SAXException, IOException
    250   {
    251 
    252     if (m_entityResolver != null)
    253     {
    254       return m_entityResolver.resolveEntity(publicId, systemId);
    255     }
    256     else
    257     {
    258       return null;
    259     }
    260   }
    261 
    262   ////////////////////////////////////////////////////////////////////
    263   // Implementation of org.xml.sax.DTDHandler.
    264   ////////////////////////////////////////////////////////////////////
    265 
    266   /**
    267    * Filter a notation declaration event.
    268    *
    269    * @param name The notation name.
    270    * @param publicId The notation's public identifier, or null.
    271    * @param systemId The notation's system identifier, or null.
    272    * @throws SAXException The client may throw
    273    *            an exception during processing.
    274    * @see org.xml.sax.DTDHandler#notationDecl
    275    */
    276   public void notationDecl(String name, String publicId, String systemId)
    277           throws SAXException
    278   {
    279 
    280     if (m_dtdHandler != null)
    281     {
    282       m_dtdHandler.notationDecl(name, publicId, systemId);
    283     }
    284   }
    285 
    286   /**
    287    * Filter an unparsed entity declaration event.
    288    *
    289    * @param name The entity name.
    290    * @param publicId The entity's public identifier, or null.
    291    * @param systemId The entity's system identifier, or null.
    292    * @param notationName The name of the associated notation.
    293    * @throws SAXException The client may throw
    294    *            an exception during processing.
    295    * @see org.xml.sax.DTDHandler#unparsedEntityDecl
    296    */
    297   public void unparsedEntityDecl(
    298           String name, String publicId, String systemId, String notationName)
    299             throws SAXException
    300   {
    301 
    302     if (m_dtdHandler != null)
    303     {
    304       m_dtdHandler.unparsedEntityDecl(name, publicId, systemId, notationName);
    305     }
    306   }
    307 
    308   ////////////////////////////////////////////////////////////////////
    309   // Implementation of org.xml.sax.ContentHandler.
    310   ////////////////////////////////////////////////////////////////////
    311 
    312   /**
    313    * Filter a new document locator event.
    314    *
    315    * @param locator The document locator.
    316    * @see org.xml.sax.ContentHandler#setDocumentLocator
    317    */
    318   public void setDocumentLocator(Locator locator)
    319   {
    320 
    321     if (DEBUG)
    322       System.out.println("TransformerHandlerImpl#setDocumentLocator: "
    323                          + locator.getSystemId());
    324 
    325     this.m_locator = locator;
    326 
    327     if(null == m_baseSystemID)
    328     {
    329       setSystemId(locator.getSystemId());
    330     }
    331 
    332     if (m_contentHandler != null)
    333     {
    334       m_contentHandler.setDocumentLocator(locator);
    335     }
    336   }
    337 
    338   /**
    339    * Filter a start document event.
    340    *
    341    * @throws SAXException The client may throw
    342    *            an exception during processing.
    343    * @see org.xml.sax.ContentHandler#startDocument
    344    */
    345   public void startDocument() throws SAXException
    346   {
    347 
    348     if (DEBUG)
    349       System.out.println("TransformerHandlerImpl#startDocument");
    350 
    351     m_insideParse = true;
    352 
    353    // Thread listener = new Thread(m_transformer);
    354 
    355     if (m_contentHandler != null)
    356     {
    357       //m_transformer.setTransformThread(listener);
    358       if(m_incremental)
    359       {
    360         m_transformer.setSourceTreeDocForThread(m_dtm.getDocument());
    361 
    362         int cpriority = Thread.currentThread().getPriority();
    363 
    364         // runTransformThread is equivalent with the 2.0.1 code,
    365         // except that the Thread may come from a pool.
    366         m_transformer.runTransformThread( cpriority );
    367       }
    368 
    369       // This is now done _last_, because IncrementalSAXSource_Filter
    370       // will immediately go into a "wait until events are requested"
    371       // pause. I believe that will close our timing window.
    372       // %REVIEW%
    373       m_contentHandler.startDocument();
    374    }
    375 
    376    //listener.setDaemon(false);
    377    //listener.start();
    378 
    379   }
    380 
    381   /**
    382    * Filter an end document event.
    383    *
    384    * @throws SAXException The client may throw
    385    *            an exception during processing.
    386    * @see org.xml.sax.ContentHandler#endDocument
    387    */
    388   public void endDocument() throws SAXException
    389   {
    390 
    391     if (DEBUG)
    392       System.out.println("TransformerHandlerImpl#endDocument");
    393 
    394     m_insideParse = false;
    395 
    396     if (m_contentHandler != null)
    397     {
    398       m_contentHandler.endDocument();
    399     }
    400 
    401     if(m_incremental)
    402     {
    403       m_transformer.waitTransformThread();
    404     }
    405     else
    406     {
    407       m_transformer.setSourceTreeDocForThread(m_dtm.getDocument());
    408       m_transformer.run();
    409     }
    410    /* Thread transformThread = m_transformer.getTransformThread();
    411 
    412     if (null != transformThread)
    413     {
    414       try
    415       {
    416 
    417         // This should wait until the transformThread is considered not alive.
    418         transformThread.join();
    419 
    420         if (!m_transformer.hasTransformThreadErrorCatcher())
    421         {
    422           Exception e = m_transformer.getExceptionThrown();
    423 
    424           if (null != e)
    425             throw new org.xml.sax.SAXException(e);
    426         }
    427 
    428         m_transformer.setTransformThread(null);
    429       }
    430       catch (InterruptedException ie){}
    431     }*/
    432   }
    433 
    434   /**
    435    * Filter a start Namespace prefix mapping event.
    436    *
    437    * @param prefix The Namespace prefix.
    438    * @param uri The Namespace URI.
    439    * @throws SAXException The client may throw
    440    *            an exception during processing.
    441    * @see org.xml.sax.ContentHandler#startPrefixMapping
    442    */
    443   public void startPrefixMapping(String prefix, String uri)
    444           throws SAXException
    445   {
    446 
    447     if (DEBUG)
    448       System.out.println("TransformerHandlerImpl#startPrefixMapping: "
    449                          + prefix + ", " + uri);
    450 
    451     if (m_contentHandler != null)
    452     {
    453       m_contentHandler.startPrefixMapping(prefix, uri);
    454     }
    455   }
    456 
    457   /**
    458    * Filter an end Namespace prefix mapping event.
    459    *
    460    * @param prefix The Namespace prefix.
    461    * @throws SAXException The client may throw
    462    *            an exception during processing.
    463    * @see org.xml.sax.ContentHandler#endPrefixMapping
    464    */
    465   public void endPrefixMapping(String prefix) throws SAXException
    466   {
    467 
    468     if (DEBUG)
    469       System.out.println("TransformerHandlerImpl#endPrefixMapping: "
    470                          + prefix);
    471 
    472     if (m_contentHandler != null)
    473     {
    474       m_contentHandler.endPrefixMapping(prefix);
    475     }
    476   }
    477 
    478   /**
    479    * Filter a start element event.
    480    *
    481    * @param uri The element's Namespace URI, or the empty string.
    482    * @param localName The element's local name, or the empty string.
    483    * @param qName The element's qualified (prefixed) name, or the empty
    484    *        string.
    485    * @param atts The element's attributes.
    486    * @throws SAXException The client may throw
    487    *            an exception during processing.
    488    * @see org.xml.sax.ContentHandler#startElement
    489    */
    490   public void startElement(
    491           String uri, String localName, String qName, Attributes atts)
    492             throws SAXException
    493   {
    494 
    495     if (DEBUG)
    496       System.out.println("TransformerHandlerImpl#startElement: " + qName);
    497 
    498     if (m_contentHandler != null)
    499     {
    500       m_contentHandler.startElement(uri, localName, qName, atts);
    501     }
    502   }
    503 
    504   /**
    505    * Filter an end element event.
    506    *
    507    * @param uri The element's Namespace URI, or the empty string.
    508    * @param localName The element's local name, or the empty string.
    509    * @param qName The element's qualified (prefixed) name, or the empty
    510    *        string.
    511    * @throws SAXException The client may throw
    512    *            an exception during processing.
    513    * @see org.xml.sax.ContentHandler#endElement
    514    */
    515   public void endElement(String uri, String localName, String qName)
    516           throws SAXException
    517   {
    518 
    519     if (DEBUG)
    520       System.out.println("TransformerHandlerImpl#endElement: " + qName);
    521 
    522     if (m_contentHandler != null)
    523     {
    524       m_contentHandler.endElement(uri, localName, qName);
    525     }
    526   }
    527 
    528   /**
    529    * Filter a character data event.
    530    *
    531    * @param ch An array of characters.
    532    * @param start The starting position in the array.
    533    * @param length The number of characters to use from the array.
    534    * @throws SAXException The client may throw
    535    *            an exception during processing.
    536    * @see org.xml.sax.ContentHandler#characters
    537    */
    538   public void characters(char ch[], int start, int length) throws SAXException
    539   {
    540 
    541     if (DEBUG)
    542       System.out.println("TransformerHandlerImpl#characters: " + start + ", "
    543                          + length);
    544 
    545     if (m_contentHandler != null)
    546     {
    547       m_contentHandler.characters(ch, start, length);
    548     }
    549   }
    550 
    551   /**
    552    * Filter an ignorable whitespace event.
    553    *
    554    * @param ch An array of characters.
    555    * @param start The starting position in the array.
    556    * @param length The number of characters to use from the array.
    557    * @throws SAXException The client may throw
    558    *            an exception during processing.
    559    * @see org.xml.sax.ContentHandler#ignorableWhitespace
    560    */
    561   public void ignorableWhitespace(char ch[], int start, int length)
    562           throws SAXException
    563   {
    564 
    565     if (DEBUG)
    566       System.out.println("TransformerHandlerImpl#ignorableWhitespace: "
    567                          + start + ", " + length);
    568 
    569     if (m_contentHandler != null)
    570     {
    571       m_contentHandler.ignorableWhitespace(ch, start, length);
    572     }
    573   }
    574 
    575   /**
    576    * Filter a processing instruction event.
    577    *
    578    * @param target The processing instruction target.
    579    * @param data The text following the target.
    580    * @throws SAXException The client may throw
    581    *            an exception during processing.
    582    * @see org.xml.sax.ContentHandler#processingInstruction
    583    */
    584   public void processingInstruction(String target, String data)
    585           throws SAXException
    586   {
    587 
    588     if (DEBUG)
    589       System.out.println("TransformerHandlerImpl#processingInstruction: "
    590                          + target + ", " + data);
    591 
    592     if (m_contentHandler != null)
    593     {
    594       m_contentHandler.processingInstruction(target, data);
    595     }
    596   }
    597 
    598   /**
    599    * Filter a skipped entity event.
    600    *
    601    * @param name The name of the skipped entity.
    602    * @throws SAXException The client may throw
    603    *            an exception during processing.
    604    * @see org.xml.sax.ContentHandler#skippedEntity
    605    */
    606   public void skippedEntity(String name) throws SAXException
    607   {
    608 
    609     if (DEBUG)
    610       System.out.println("TransformerHandlerImpl#skippedEntity: " + name);
    611 
    612     if (m_contentHandler != null)
    613     {
    614       m_contentHandler.skippedEntity(name);
    615     }
    616   }
    617 
    618   ////////////////////////////////////////////////////////////////////
    619   // Implementation of org.xml.sax.ErrorHandler.
    620   ////////////////////////////////////////////////////////////////////
    621 
    622   /**
    623    * Filter a warning event.
    624    *
    625    * @param e The nwarning as an exception.
    626    * @throws SAXException The client may throw
    627    *            an exception during processing.
    628    * @see org.xml.sax.ErrorHandler#warning
    629    */
    630   public void warning(SAXParseException e) throws SAXException
    631   {
    632     // This is not great, but we really would rather have the error
    633     // handler be the error listener if it is a error handler.  Coroutine's fatalError
    634     // can't really be configured, so I think this is the best thing right now
    635     // for error reporting.  Possibly another JAXP 1.1 hole.  -sb
    636     javax.xml.transform.ErrorListener errorListener = m_transformer.getErrorListener();
    637     if(errorListener instanceof ErrorHandler)
    638     {
    639       ((ErrorHandler)errorListener).warning(e);
    640     }
    641     else
    642     {
    643       try
    644       {
    645         errorListener.warning(new javax.xml.transform.TransformerException(e));
    646       }
    647       catch(javax.xml.transform.TransformerException te)
    648       {
    649         throw e;
    650       }
    651     }
    652   }
    653 
    654   /**
    655    * Filter an error event.
    656    *
    657    * @param e The error as an exception.
    658    * @throws SAXException The client may throw
    659    *            an exception during processing.
    660    * @see org.xml.sax.ErrorHandler#error
    661    */
    662   public void error(SAXParseException e) throws SAXException
    663   {
    664     // %REVIEW% I don't think this should be called.  -sb
    665     // clearCoRoutine(e);
    666 
    667     // This is not great, but we really would rather have the error
    668     // handler be the error listener if it is a error handler.  Coroutine's fatalError
    669     // can't really be configured, so I think this is the best thing right now
    670     // for error reporting.  Possibly another JAXP 1.1 hole.  -sb
    671     javax.xml.transform.ErrorListener errorListener = m_transformer.getErrorListener();
    672     if(errorListener instanceof ErrorHandler)
    673     {
    674       ((ErrorHandler)errorListener).error(e);
    675       if(null != m_errorHandler)
    676         m_errorHandler.error(e); // may not be called.
    677     }
    678     else
    679     {
    680       try
    681       {
    682         errorListener.error(new javax.xml.transform.TransformerException(e));
    683         if(null != m_errorHandler)
    684           m_errorHandler.error(e); // may not be called.
    685       }
    686       catch(javax.xml.transform.TransformerException te)
    687       {
    688         throw e;
    689       }
    690     }
    691   }
    692 
    693   /**
    694    * Filter a fatal error event.
    695    *
    696    * @param e The error as an exception.
    697    * @throws SAXException The client may throw
    698    *            an exception during processing.
    699    * @see org.xml.sax.ErrorHandler#fatalError
    700    */
    701   public void fatalError(SAXParseException e) throws SAXException
    702   {
    703     if(null != m_errorHandler)
    704     {
    705       try
    706       {
    707         m_errorHandler.fatalError(e);
    708       }
    709       catch(SAXParseException se)
    710       {
    711         // ignore
    712       }
    713       // clearCoRoutine(e);
    714     }
    715 
    716     // This is not great, but we really would rather have the error
    717     // handler be the error listener if it is a error handler.  Coroutine's fatalError
    718     // can't really be configured, so I think this is the best thing right now
    719     // for error reporting.  Possibly another JAXP 1.1 hole.  -sb
    720     javax.xml.transform.ErrorListener errorListener = m_transformer.getErrorListener();
    721 
    722     if(errorListener instanceof ErrorHandler)
    723     {
    724       ((ErrorHandler)errorListener).fatalError(e);
    725       if(null != m_errorHandler)
    726         m_errorHandler.fatalError(e); // may not be called.
    727     }
    728     else
    729     {
    730       try
    731       {
    732         errorListener.fatalError(new javax.xml.transform.TransformerException(e));
    733         if(null != m_errorHandler)
    734           m_errorHandler.fatalError(e); // may not be called.
    735       }
    736       catch(javax.xml.transform.TransformerException te)
    737       {
    738         throw e;
    739       }
    740     }
    741   }
    742 
    743   ////////////////////////////////////////////////////////////////////
    744   // Implementation of org.xml.sax.ext.LexicalHandler.
    745   ////////////////////////////////////////////////////////////////////
    746 
    747   /**
    748    * Report the start of DTD declarations, if any.
    749    *
    750    * <p>Any declarations are assumed to be in the internal subset
    751    * unless otherwise indicated by a {@link #startEntity startEntity}
    752    * event.</p>
    753    *
    754    * <p>Note that the start/endDTD events will appear within
    755    * the start/endDocument events from ContentHandler and
    756    * before the first startElement event.</p>
    757    *
    758    * @param name The document type name.
    759    * @param publicId The declared public identifier for the
    760    *        external DTD subset, or null if none was declared.
    761    * @param systemId The declared system identifier for the
    762    *        external DTD subset, or null if none was declared.
    763    * @throws SAXException The application may raise an
    764    *            exception.
    765    * @see #endDTD
    766    * @see #startEntity
    767    */
    768   public void startDTD(String name, String publicId, String systemId)
    769           throws SAXException
    770   {
    771 
    772     if (DEBUG)
    773       System.out.println("TransformerHandlerImpl#startDTD: " + name + ", "
    774                          + publicId + ", " + systemId);
    775 
    776     if (null != m_lexicalHandler)
    777     {
    778       m_lexicalHandler.startDTD(name, publicId, systemId);
    779     }
    780   }
    781 
    782   /**
    783    * Report the end of DTD declarations.
    784    *
    785    * @throws SAXException The application may raise an exception.
    786    * @see #startDTD
    787    */
    788   public void endDTD() throws SAXException
    789   {
    790 
    791     if (DEBUG)
    792       System.out.println("TransformerHandlerImpl#endDTD");
    793 
    794     if (null != m_lexicalHandler)
    795     {
    796       m_lexicalHandler.endDTD();
    797     }
    798   }
    799 
    800   /**
    801    * Report the beginning of an entity in content.
    802    *
    803    * <p><strong>NOTE:</entity> entity references in attribute
    804    * values -- and the start and end of the document entity --
    805    * are never reported.</p>
    806    *
    807    * <p>The start and end of the external DTD subset are reported
    808    * using the pseudo-name "[dtd]".  All other events must be
    809    * properly nested within start/end entity events.</p>
    810    *
    811    * <p>Note that skipped entities will be reported through the
    812    * {@link org.xml.sax.ContentHandler#skippedEntity skippedEntity}
    813    * event, which is part of the ContentHandler interface.</p>
    814    *
    815    * @param name The name of the entity.  If it is a parameter
    816    *        entity, the name will begin with '%'.
    817    * @throws SAXException The application may raise an exception.
    818    * @see #endEntity
    819    * @see org.xml.sax.ext.DeclHandler#internalEntityDecl
    820    * @see org.xml.sax.ext.DeclHandler#externalEntityDecl
    821    */
    822   public void startEntity(String name) throws SAXException
    823   {
    824 
    825     if (DEBUG)
    826       System.out.println("TransformerHandlerImpl#startEntity: " + name);
    827 
    828     if (null != m_lexicalHandler)
    829     {
    830       m_lexicalHandler.startEntity(name);
    831     }
    832   }
    833 
    834   /**
    835    * Report the end of an entity.
    836    *
    837    * @param name The name of the entity that is ending.
    838    * @throws SAXException The application may raise an exception.
    839    * @see #startEntity
    840    */
    841   public void endEntity(String name) throws SAXException
    842   {
    843 
    844     if (DEBUG)
    845       System.out.println("TransformerHandlerImpl#endEntity: " + name);
    846 
    847     if (null != m_lexicalHandler)
    848     {
    849       m_lexicalHandler.endEntity(name);
    850     }
    851   }
    852 
    853   /**
    854    * Report the start of a CDATA section.
    855    *
    856    * <p>The contents of the CDATA section will be reported through
    857    * the regular {@link org.xml.sax.ContentHandler#characters
    858    * characters} event.</p>
    859    *
    860    * @throws SAXException The application may raise an exception.
    861    * @see #endCDATA
    862    */
    863   public void startCDATA() throws SAXException
    864   {
    865 
    866     if (DEBUG)
    867       System.out.println("TransformerHandlerImpl#startCDATA");
    868 
    869     if (null != m_lexicalHandler)
    870     {
    871       m_lexicalHandler.startCDATA();
    872     }
    873   }
    874 
    875   /**
    876    * Report the end of a CDATA section.
    877    *
    878    * @throws SAXException The application may raise an exception.
    879    * @see #startCDATA
    880    */
    881   public void endCDATA() throws SAXException
    882   {
    883 
    884     if (DEBUG)
    885       System.out.println("TransformerHandlerImpl#endCDATA");
    886 
    887     if (null != m_lexicalHandler)
    888     {
    889       m_lexicalHandler.endCDATA();
    890     }
    891   }
    892 
    893   /**
    894    * Report an XML comment anywhere in the document.
    895    *
    896    * <p>This callback will be used for comments inside or outside the
    897    * document element, including comments in the external DTD
    898    * subset (if read).</p>
    899    *
    900    * @param ch An array holding the characters in the comment.
    901    * @param start The starting position in the array.
    902    * @param length The number of characters to use from the array.
    903    * @throws SAXException The application may raise an exception.
    904    */
    905   public void comment(char ch[], int start, int length) throws SAXException
    906   {
    907 
    908     if (DEBUG)
    909       System.out.println("TransformerHandlerImpl#comment: " + start + ", "
    910                          + length);
    911 
    912     if (null != m_lexicalHandler)
    913     {
    914       m_lexicalHandler.comment(ch, start, length);
    915     }
    916   }
    917 
    918   ////////////////////////////////////////////////////////////////////
    919   // Implementation of org.xml.sax.ext.DeclHandler.
    920   ////////////////////////////////////////////////////////////////////
    921 
    922   /**
    923    * Report an element type declaration.
    924    *
    925    * <p>The content model will consist of the string "EMPTY", the
    926    * string "ANY", or a parenthesised group, optionally followed
    927    * by an occurrence indicator.  The model will be normalized so
    928    * that all whitespace is removed,and will include the enclosing
    929    * parentheses.</p>
    930    *
    931    * @param name The element type name.
    932    * @param model The content model as a normalized string.
    933    * @throws SAXException The application may raise an exception.
    934    */
    935   public void elementDecl(String name, String model) throws SAXException
    936   {
    937 
    938     if (DEBUG)
    939       System.out.println("TransformerHandlerImpl#elementDecl: " + name + ", "
    940                          + model);
    941 
    942     if (null != m_declHandler)
    943     {
    944       m_declHandler.elementDecl(name, model);
    945     }
    946   }
    947 
    948   /**
    949    * Report an attribute type declaration.
    950    *
    951    * <p>Only the effective (first) declaration for an attribute will
    952    * be reported.  The type will be one of the strings "CDATA",
    953    * "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY",
    954    * "ENTITIES", or "NOTATION", or a parenthesized token group with
    955    * the separator "|" and all whitespace removed.</p>
    956    *
    957    * @param eName The name of the associated element.
    958    * @param aName The name of the attribute.
    959    * @param type A string representing the attribute type.
    960    * @param valueDefault A string representing the attribute default
    961    *        ("#IMPLIED", "#REQUIRED", or "#FIXED") or null if
    962    *        none of these applies.
    963    * @param value A string representing the attribute's default value,
    964    *        or null if there is none.
    965    * @throws SAXException The application may raise an exception.
    966    */
    967   public void attributeDecl(
    968           String eName, String aName, String type, String valueDefault, String value)
    969             throws SAXException
    970   {
    971 
    972     if (DEBUG)
    973       System.out.println("TransformerHandlerImpl#attributeDecl: " + eName
    974                          + ", " + aName + ", etc...");
    975 
    976     if (null != m_declHandler)
    977     {
    978       m_declHandler.attributeDecl(eName, aName, type, valueDefault, value);
    979     }
    980   }
    981 
    982   /**
    983    * Report an internal entity declaration.
    984    *
    985    * <p>Only the effective (first) declaration for each entity
    986    * will be reported.</p>
    987    *
    988    * @param name The name of the entity.  If it is a parameter
    989    *        entity, the name will begin with '%'.
    990    * @param value The replacement text of the entity.
    991    * @throws SAXException The application may raise an exception.
    992    * @see #externalEntityDecl
    993    * @see org.xml.sax.DTDHandler#unparsedEntityDecl
    994    */
    995   public void internalEntityDecl(String name, String value)
    996           throws SAXException
    997   {
    998 
    999     if (DEBUG)
   1000       System.out.println("TransformerHandlerImpl#internalEntityDecl: " + name
   1001                          + ", " + value);
   1002 
   1003     if (null != m_declHandler)
   1004     {
   1005       m_declHandler.internalEntityDecl(name, value);
   1006     }
   1007   }
   1008 
   1009   /**
   1010    * Report a parsed external entity declaration.
   1011    *
   1012    * <p>Only the effective (first) declaration for each entity
   1013    * will be reported.</p>
   1014    *
   1015    * @param name The name of the entity.  If it is a parameter
   1016    *        entity, the name will begin with '%'.
   1017    * @param publicId The declared public identifier of the entity, or
   1018    *        null if none was declared.
   1019    * @param systemId The declared system identifier of the entity.
   1020    * @throws SAXException The application may raise an exception.
   1021    * @see #internalEntityDecl
   1022    * @see org.xml.sax.DTDHandler#unparsedEntityDecl
   1023    */
   1024   public void externalEntityDecl(
   1025           String name, String publicId, String systemId) throws SAXException
   1026   {
   1027 
   1028     if (DEBUG)
   1029       System.out.println("TransformerHandlerImpl#externalEntityDecl: " + name
   1030                          + ", " + publicId + ", " + systemId);
   1031 
   1032     if (null != m_declHandler)
   1033     {
   1034       m_declHandler.externalEntityDecl(name, publicId, systemId);
   1035     }
   1036   }
   1037 
   1038   ////////////////////////////////////////////////////////////////////
   1039   // Internal state.
   1040   ////////////////////////////////////////////////////////////////////
   1041 
   1042   /** Set to true for diagnostics output.         */
   1043   private static boolean DEBUG = false;
   1044 
   1045   /**
   1046    * The transformer this will use to transform a
   1047    * source tree into a result tree.
   1048    */
   1049   private TransformerImpl m_transformer;
   1050 
   1051   /** The system ID to use as a base for relative URLs. */
   1052   private String m_baseSystemID;
   1053 
   1054   /** The result for the transformation. */
   1055   private Result m_result = null;
   1056 
   1057   /** The locator for this TransformerHandler. */
   1058   private Locator m_locator = null;
   1059 
   1060   /** The entity resolver to aggregate to. */
   1061   private EntityResolver m_entityResolver = null;
   1062 
   1063   /** The DTD handler to aggregate to. */
   1064   private DTDHandler m_dtdHandler = null;
   1065 
   1066   /** The content handler to aggregate to. */
   1067   private ContentHandler m_contentHandler = null;
   1068 
   1069   /** The error handler to aggregate to. */
   1070   private ErrorHandler m_errorHandler = null;
   1071 
   1072   /** The lexical handler to aggregate to. */
   1073   private LexicalHandler m_lexicalHandler = null;
   1074 
   1075   /** The decl handler to aggregate to. */
   1076   private DeclHandler m_declHandler = null;
   1077 
   1078   /** The Document Table Instance we are transforming. */
   1079   DTM m_dtm;
   1080 }
   1081