code: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements. See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership. The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the  "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  /*
   * $Id$
   */
  
  package org.apache.xml.serializer;
  
  import java.io.IOException;
  import java.io.OutputStream;
  import java.io.Writer;
  import java.util.Properties;
  
  import javax.xml.transform.Result;
  
  import org.w3c.dom.Node;
  import org.xml.sax.Attributes;
  import org.xml.sax.ContentHandler;
  import org.xml.sax.Locator;
  import org.xml.sax.SAXException;
  import org.xml.sax.ext.LexicalHandler;
  
  /**
   * This class accepts SAX-like calls, then sends true SAX calls to a
   * wrapped SAX handler.  There is optimization done knowing that the ultimate
   * output is HTML.
   * 
   * This class is not a public API.
   * 
   * @deprecated As of Xalan 2.7.1, replaced by the use of {@link ToXMLSAXHandler}.
   * 
   * @xsl.usage internal
   */
  public final class ToHTMLSAXHandler extends ToSAXHandler
  {
  	/**
  	 *  Handle document type declaration (for first element only)
  	 */
  	private boolean m_dtdHandled = false;
  	
      /**
       * Keeps track of whether output escaping is currently enabled
       */
      protected boolean m_escapeSetting = true;
  
      /**
       * Returns null.
       * @return null
       * @see Serializer#getOutputFormat()
       */
      public Properties getOutputFormat()
      {
          return null;
      }
  
      /**
       * Reurns null
       * @return null
       * @see Serializer#getOutputStream()
       */
      public OutputStream getOutputStream()
      {
          return null;
      }
  
      /**
       * Returns null
       * @return null
       * @see Serializer#getWriter()
       */
      public Writer getWriter()
      {
          return null;
      }
  
      /**
       * Does nothing.
       *
       */
      public void indent(int n) throws SAXException
      {
      }
  
      /**
       * Does nothing.
       * @see DOMSerializer#serialize(Node)
       */
      public void serialize(Node node) throws IOException
      {
          return;
      }
  
      /**
       * Turns special character escaping on/off.
       *
       *
       * @param escape true if escaping is to be set on.
       *
       * @see SerializationHandler#setEscaping(boolean)
       */
      public boolean setEscaping(boolean escape) throws SAXException
      {
          boolean oldEscapeSetting = m_escapeSetting;
          m_escapeSetting = escape;
  
          if (escape) {
              processingInstruction(Result.PI_ENABLE_OUTPUT_ESCAPING, "");
          } else {
              processingInstruction(Result.PI_DISABLE_OUTPUT_ESCAPING, "");
          }
  
          return oldEscapeSetting;
      }
  
      /**
       * Does nothing
       * @param indent the number of spaces to indent per indentation level
       * (ignored)
       * @see SerializationHandler#setIndent(boolean)
       */
      public void setIndent(boolean indent)
      {
      }
  
      /**
       * Does nothing.
       * @param format this parameter is not used
       * @see Serializer#setOutputFormat(Properties)
       */
      public void setOutputFormat(Properties format)
      {
      }
  
      /**
       * Does nothing.
       * @param output this parameter is ignored
       * @see Serializer#setOutputStream(OutputStream)
       */
      public void setOutputStream(OutputStream output)
      {
      }
  
  
      /**
       * Does nothing.
       * @param writer this parameter is ignored.
       * @see Serializer#setWriter(Writer)
       */
      public void setWriter(Writer writer)
      {
      }
  
      /**
       * @see org.xml.sax.ext.DeclHandler#attributeDecl(String, String, String, String, String)
       */
      /**
       * Does nothing.
       *
       * @param eName this parameter is ignored
       * @param aName this parameter is ignored
       * @param type this parameter is ignored
       * @param valueDefault this parameter is ignored
       * @param value this parameter is ignored
       * @see org.xml.sax.ext.DeclHandler#attributeDecl(String, String, String,String,String)
       */    
      public void attributeDecl(
          String eName,
          String aName,
          String type,
          String valueDefault,
          String value)
          throws SAXException
      {
      }
  
  
      /**
       * Does nothing.
       * @see org.xml.sax.ext.DeclHandler#elementDecl(String, String)
       */    
      public void elementDecl(String name, String model) throws SAXException
      {
          return;
      }
  
      /**
       * @see org.xml.sax.ext.DeclHandler#externalEntityDecl(String, String, String)
       */
      public void externalEntityDecl(String arg0, String arg1, String arg2)
          throws SAXException
      {
      }
  
      /**
       * Does nothing.
       *
       * @see org.xml.sax.DTDHandler#unparsedEntityDecl
       */
      public void internalEntityDecl(String name, String value)
          throws SAXException
      {
      }
  
      /**
       * Receive notification of the end of an element.
       *
       * <p>The SAX parser will invoke this method at the end of every
       * element in the XML document; there will be a corresponding
       * startElement() event for every endElement() event (even when the
       * element is empty).</p>
       *
       * <p>If the element name has a namespace prefix, the prefix will
       * still be attached to the name.</p>
       *
       *
       * @param uri The Namespace URI, or the empty string if the
       *        element has no Namespace URI or if Namespace
       *        processing is not being performed.
       * @param localName The local name (without prefix), or the
       *        empty string if Namespace processing is not being
       *        performed.
       * @param qName The qualified name (with prefix), or the
       *        empty string if qualified names are not available.
       * @throws org.xml.sax.SAXException Any SAX exception, possibly
       *            wrapping another exception.
       * @see org.xml.sax.ContentHandler#endElement(String, String, String)
       */
      public void endElement(String uri, String localName, String qName)
          throws SAXException
      {
          flushPending();
          m_saxHandler.endElement(uri, localName, qName);
          
          // time to fire off endElement event
          if (m_tracer != null)
              super.fireEndElem(qName);
      }
  
      /**
       * Does nothing.
       */
      public void endPrefixMapping(String prefix) throws SAXException
      {
      }
  
      /**
       * Does nothing.
       * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
       */
      public void ignorableWhitespace(char[] ch, int start, int length)
          throws SAXException
      {
      }
      
      /**
       * Receive notification of a processing instruction.
       *
       * <p>The Parser will invoke this method once for each processing
       * instruction found: note that processing instructions may occur
       * before or after the main document element.</p>
       *
       * <p>A SAX parser should never report an XML declaration (XML 1.0,
       * section 2.8) or a text declaration (XML 1.0, section 4.3.1)
       * using this method.</p>
       *
       * @param target The processing instruction target.
       * @param data The processing instruction data, or null if
       *        none was supplied.
       * @throws org.xml.sax.SAXException Any SAX exception, possibly
       *            wrapping another exception.
       *
       * @throws org.xml.sax.SAXException
       * @see org.xml.sax.ContentHandler#processingInstruction(String, String)
       */
      public void processingInstruction(String target, String data)
          throws SAXException
      {
          flushPending();
          m_saxHandler.processingInstruction(target,data);
  
  		// time to fire off processing instruction event
  		
          if (m_tracer != null)		
  		    super.fireEscapingEvent(target,data);        
      }
  
      /**
       * Does nothing.  
       * @see org.xml.sax.ContentHandler#setDocumentLocator(Locator)
       */
      public void setDocumentLocator(Locator arg0)
      {
          // do nothing
      }
  
      /**
       * Does nothing.
       * @see org.xml.sax.ContentHandler#skippedEntity(String)
       */
      public void skippedEntity(String arg0) throws SAXException
      {
      }
  
      /**
       * Receive notification of the beginning of an element, although this is a
       * SAX method additional namespace or attribute information can occur before
       * or after this call, that is associated with this element.
       *
       *
       * @param namespaceURI The Namespace URI, or the empty string if the
       *        element has no Namespace URI or if Namespace
       *        processing is not being performed.
       * @param localName The local name (without prefix), or the
       *        empty string if Namespace processing is not being
       *        performed.
       * @param qName The elements name.
       * @param atts The attributes attached to the element, if any.
       * @throws org.xml.sax.SAXException Any SAX exception, possibly
       *            wrapping another exception.
       * @see org.xml.sax.ContentHandler#startElement
       * @see org.xml.sax.ContentHandler#endElement
       * @see org.xml.sax.AttributeList
       *
       * @throws org.xml.sax.SAXException
       *
       * @see org.xml.sax.ContentHandler#startElement(String, String, String, Attributes)
       */
      public void startElement(
          String namespaceURI,
          String localName,
          String qName,
          Attributes atts)
          throws SAXException
      {
          flushPending();
          super.startElement(namespaceURI, localName, qName, atts);
          m_saxHandler.startElement(namespaceURI, localName, qName, atts);
          m_elemContext.m_startTagOpen = false;
      }
  
      /**
       * Receive notification of a comment anywhere in the document. This callback
       * will be used for comments inside or outside the document element.
       * @param ch An array holding the characters in the comment.
       * @param start The starting position in the array.
       * @param length The number of characters to use from the array.
       * @throws org.xml.sax.SAXException The application may raise an exception.
       *
       * @see org.xml.sax.ext.LexicalHandler#comment(char[], int, int)
       */
      public void comment(char[] ch, int start, int length) throws SAXException
      {
          flushPending();
          if (m_lexHandler != null)
              m_lexHandler.comment(ch, start, length);
  
          // time to fire off comment event
          if (m_tracer != null)
              super.fireCommentEvent(ch, start, length);
          return;
      }
  
      /**
       * Does nothing.
       * @see org.xml.sax.ext.LexicalHandler#endCDATA()
       */
      public void endCDATA() throws SAXException
      {
          return;
      }
  
      /**
       * Does nothing.
       * @see org.xml.sax.ext.LexicalHandler#endDTD()
       */
      public void endDTD() throws SAXException
      {
      }
  
      /**
       * Does nothing.
       * @see org.xml.sax.ext.LexicalHandler#startCDATA()
       */
      public void startCDATA() throws SAXException
      {
      }
  
      /**
       * Does nothing.
       * @see org.xml.sax.ext.LexicalHandler#startEntity(String)
       */
      public void startEntity(String arg0) throws SAXException
      {
      }
  
      /**
       * Receive notification of the end of a document.
       *
       * <p>The SAX parser will invoke this method only once, and it will
       * be the last method invoked during the parse.  The parser shall
       * not invoke this method until it has either abandoned parsing
       * (because of an unrecoverable error) or reached the end of
       * input.</p>
       *
       * @throws org.xml.sax.SAXException Any SAX exception, possibly
       *            wrapping another exception.
       *
       * @throws org.xml.sax.SAXException
       *
       *
       */
      public void endDocument() throws SAXException
      {
          flushPending();
  
          // Close output document
          m_saxHandler.endDocument();
  
          if (m_tracer != null)
              super.fireEndDoc();        
      }
  
      /**
       * This method is called when all the data needed for a call to the
       * SAX handler's startElement() method has been gathered.
       */
      protected void closeStartTag() throws SAXException
      {
  
          m_elemContext.m_startTagOpen = false;
  
          // Now is time to send the startElement event
          m_saxHandler.startElement(
              EMPTYSTRING,
              m_elemContext.m_elementName,
              m_elemContext.m_elementName,
              m_attributes);
          m_attributes.clear();       
  
      }
  
      /**
       * Do nothing.
       * @see SerializationHandler#close()
       */
      public void close()
      {
          return;
      }
  
      /**
       * Receive notification of character data.
       *
       * @param chars The string of characters to process.
       *
       * @throws org.xml.sax.SAXException
       *
       * @see ExtendedContentHandler#characters(String)
       */
      public void characters(final String chars) throws SAXException
      {
          final int length = chars.length();
          if (length > m_charsBuff.length)
          {
              m_charsBuff = new char[length * 2 + 1];
          }
          chars.getChars(0, length, m_charsBuff, 0);        
          this.characters(m_charsBuff, 0, length);
      }
  
  
      /**
       * A constructor
       * @param handler the wrapped SAX content handler
       * @param encoding the encoding of the output HTML document
       */
      public ToHTMLSAXHandler(ContentHandler handler, String encoding)
      {
          super(handler,encoding);
      }
      /**
       * A constructor.
       * @param handler the wrapped SAX content handler
       * @param lex the wrapped lexical handler
       * @param encoding the encoding of the output HTML document
       */
      public ToHTMLSAXHandler(
          ContentHandler handler,
          LexicalHandler lex,
          String encoding)
      {
          super(handler,lex,encoding);
      }
  
      /**
       * An element starts, but attributes are not fully known yet.
       *
       * @param elementNamespaceURI the URI of the namespace of the element
       * (optional)
       * @param elementLocalName the element name, but without prefix
       * (optional)
       * @param elementName the element name, with prefix, if any (required)
       *
       * @see ExtendedContentHandler#startElement(String)
       */
      public void startElement(
          String elementNamespaceURI,
          String elementLocalName,
          String elementName) throws SAXException
      {
  
          super.startElement(elementNamespaceURI, elementLocalName, elementName);
  
          flushPending();
  
          // Handle document type declaration (for first element only)
          if (!m_dtdHandled)
          {
              String doctypeSystem = getDoctypeSystem();
              String doctypePublic = getDoctypePublic();
              if ((doctypeSystem != null) || (doctypePublic != null)) {
                  if (m_lexHandler != null)
                      m_lexHandler.startDTD(
                          elementName,
                          doctypePublic,
                          doctypeSystem);
              }
  			m_dtdHandled = true;
          }
          m_elemContext = m_elemContext.push(elementNamespaceURI, elementLocalName, elementName);
      }
      /**
       * An element starts, but attributes are not fully known yet.
       *
       * @param elementName the element name, with prefix, if any
       *
       * @see ExtendedContentHandler#startElement(String)
       */
      public void startElement(String elementName) throws SAXException
      {
          this.startElement(null,null, elementName);
      }
      
      /**
       * Receive notification of the end of an element.
       * @param elementName The element type name
       * @throws org.xml.sax.SAXException Any SAX exception, possibly
       *     wrapping another exception.
       *
       * @see ExtendedContentHandler#endElement(String)
       */
      public void endElement(String elementName) throws SAXException
      {
          flushPending();
          m_saxHandler.endElement(EMPTYSTRING, elementName, elementName);
  
          // time to fire off endElement event
  		if (m_tracer != null)
              super.fireEndElem(elementName);        
      }
  
      /**
       * Receive notification of character data.
       *
       * <p>The Parser will call this method to report each chunk of
       * character data.  SAX parsers may return all contiguous character
       * data in a single chunk, or they may split it into several
       * chunks; however, all of the characters in any single event
       * must come from the same external entity, so that the Locator
       * provides useful information.</p>
       *
       * <p>The application must not attempt to read from the array
       * outside of the specified range.</p>
       *
       * <p>Note that some parsers will report whitespace using the
       * ignorableWhitespace() method rather than this one (validating
       * parsers must do so).</p>
       *
       * @param ch The characters from the XML document.
       * @param off The start position in the array.
       * @param len The number of characters to read from the array.
       * @throws org.xml.sax.SAXException Any SAX exception, possibly
       *            wrapping another exception.
       * @see #ignorableWhitespace
       * @see org.xml.sax.Locator
       *
       * @throws org.xml.sax.SAXException
       *
       * @see org.xml.sax.ContentHandler#characters(char[], int, int)
       */
      public void characters(char[] ch, int off, int len) throws SAXException
      {
  
          flushPending();
          m_saxHandler.characters(ch, off, len);
  
          // time to fire off characters event
  		if (m_tracer != null)
              super.fireCharEvent(ch, off, len);        
      }
  
      /**
       * This method flushes any pending events, which can be startDocument()
       * closing the opening tag of an element, or closing an open CDATA section.
       */
      public void flushPending() throws SAXException
      {
  		if (m_needToCallStartDocument)
  		{
  			startDocumentInternal();
  			m_needToCallStartDocument = false;
  		}       	
          // Close any open element
          if (m_elemContext.m_startTagOpen)
          {
              closeStartTag();
              m_elemContext.m_startTagOpen = false;
          }
      }
      /**
       * Handle a prefix/uri mapping, which is associated with a startElement()
       * that is soon to follow. Need to close any open start tag to make
       * sure than any name space attributes due to this event are associated wih
       * the up comming element, not the current one.
       * @see ExtendedContentHandler#startPrefixMapping
       *
       * @param prefix The Namespace prefix being declared.
       * @param uri The Namespace URI the prefix is mapped to.
       * @param shouldFlush true if any open tags need to be closed first, this
       * will impact which element the mapping applies to (open parent, or its up
       * comming child)
       * @return returns true if the call made a change to the current
       * namespace information, false if it did not change anything, e.g. if the
       * prefix/namespace mapping was already in scope from before.
       *
       * @throws org.xml.sax.SAXException The client may throw
       *            an exception during processing.
       */    
      public boolean startPrefixMapping(
          String prefix,
          String uri,
          boolean shouldFlush)
          throws SAXException
      {
          // no namespace support for HTML
          if (shouldFlush) 
              flushPending();   
          m_saxHandler.startPrefixMapping(prefix,uri);
          return false;
      }
  
      /**
       * Begin the scope of a prefix-URI Namespace mapping
       * just before another element is about to start.
       * This call will close any open tags so that the prefix mapping
       * will not apply to the current element, but the up comming child.
       *
       * @see org.xml.sax.ContentHandler#startPrefixMapping
       *
       * @param prefix The Namespace prefix being declared.
       * @param uri The Namespace URI the prefix is mapped to.
       *
       * @throws org.xml.sax.SAXException The client may throw
       *            an exception during processing.
       *
       */
      public void startPrefixMapping(String prefix, String uri)
          throws org.xml.sax.SAXException
      {
          startPrefixMapping(prefix,uri,true);        
      }
  
      /**
       * This method is used when a prefix/uri namespace mapping
       * is indicated after the element was started with a
       * startElement() and before and endElement().
       * startPrefixMapping(prefix,uri) would be used before the
       * startElement() call.
       * @param prefix the prefix associated with the given URI.
       * @param uri the URI of the namespace
       *
       * @see ExtendedContentHandler#namespaceAfterStartElement(String, String)
       */
      public void namespaceAfterStartElement(
          final String prefix,
          final String uri)
          throws SAXException
      {
          // hack for XSLTC with finding URI for default namespace
          if (m_elemContext.m_elementURI == null)
          {
              String prefix1 = getPrefixPart(m_elemContext.m_elementName);
              if (prefix1 == null && EMPTYSTRING.equals(prefix))
              {
                  // the elements URI is not known yet, and it
                  // doesn't have a prefix, and we are currently
                  // setting the uri for prefix "", so we have
                  // the uri for the element... lets remember it
                  m_elemContext.m_elementURI = uri;
              }
          }       
          startPrefixMapping(prefix,uri,false);
      }
      
      /**
       * Try's to reset the super class and reset this class for 
       * re-use, so that you don't need to create a new serializer 
       * (mostly for performance reasons).
       * 
       * @return true if the class was successfuly reset.
       * @see Serializer#reset()
       */
      public boolean reset()
      {
          boolean wasReset = false;
          if (super.reset())
          {
              resetToHTMLSAXHandler();
              wasReset = true;
          }
          return wasReset;
      }
      
      /**
       * Reset all of the fields owned by ToHTMLSAXHandler class
       *
       */
      private void resetToHTMLSAXHandler()
      {
          this.m_dtdHandled = false;
          this.m_escapeSetting = true;
      }  
  }
  