001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: TransformerHandlerImpl.java 468645 2006-10-28 06:57:24Z minchau $
020     */
021    package org.apache.xalan.transformer;
022    
023    import java.io.IOException;
024    
025    import javax.xml.transform.Result;
026    import javax.xml.transform.Transformer;
027    import javax.xml.transform.sax.TransformerHandler;
028    
029    import org.apache.xalan.res.XSLMessages;
030    import org.apache.xalan.res.XSLTErrorResources;
031    import org.apache.xml.dtm.DTM;
032    import org.apache.xml.dtm.DTMManager;
033    import org.apache.xml.dtm.ref.IncrementalSAXSource_Filter;
034    import org.apache.xml.dtm.ref.sax2dtm.SAX2DTM;
035    import org.apache.xpath.XPathContext;
036    
037    import org.xml.sax.Attributes;
038    import org.xml.sax.ContentHandler;
039    import org.xml.sax.DTDHandler;
040    import org.xml.sax.EntityResolver;
041    import org.xml.sax.ErrorHandler;
042    import org.xml.sax.InputSource;
043    import org.xml.sax.Locator;
044    import org.xml.sax.SAXException;
045    import org.xml.sax.SAXParseException;
046    import org.xml.sax.ext.DeclHandler;
047    import org.xml.sax.ext.LexicalHandler;
048    import org.apache.xml.serializer.SerializationHandler;
049    
050    
051    /**
052     * A TransformerHandler
053     * listens for SAX ContentHandler parse events and transforms
054     * them to a Result.
055     */
056    public class TransformerHandlerImpl
057            implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler,
058                       LexicalHandler, TransformerHandler, DeclHandler
059    {
060        /**
061         * The flag for the setting of the optimize feature;
062         */    
063        private final boolean m_optimizer;
064    
065        /**
066         * The flag for the setting of the incremental feature;
067         */    
068        private final boolean m_incremental;
069    
070        /**
071         * The flag for the setting of the source_location feature;
072         */  
073        private final boolean m_source_location;
074      
075      private boolean m_insideParse = false;
076    
077      ////////////////////////////////////////////////////////////////////
078      // Constructors.
079      ////////////////////////////////////////////////////////////////////
080    
081      /**
082       * Construct a TransformerHandlerImpl.
083       *
084       * @param transformer Non-null reference to the Xalan transformer impl.
085       * @param doFragment True if the result should be a document fragement.
086       * @param baseSystemID  The system ID to use as the base for relative URLs.
087       */
088      public TransformerHandlerImpl(TransformerImpl transformer,
089                                    boolean doFragment, String baseSystemID)
090      {
091    
092        super();
093    
094        m_transformer = transformer;
095        m_baseSystemID = baseSystemID;
096    
097        XPathContext xctxt = transformer.getXPathContext();
098        DTM dtm = xctxt.getDTM(null, true, transformer, true, true);
099        
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    }