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: ProcessorCharacters.java 468640 2006-10-28 06:53:53Z minchau $
020     */
021    package org.apache.xalan.processor;
022    
023    import javax.xml.transform.TransformerException;
024    
025    import org.apache.xalan.templates.ElemTemplateElement;
026    import org.apache.xalan.templates.ElemText;
027    import org.apache.xalan.templates.ElemTextLiteral;
028    import org.apache.xml.utils.XMLCharacterRecognizer;
029    
030    import org.w3c.dom.Node;
031    
032    /**
033     * This class processes character events for a XSLT template element.
034     * @see <a href="http://www.w3.org/TR/xslt#dtd">XSLT DTD</a>
035     * @see <a href="http://www.w3.org/TR/xslt#section-Creating-the-Result-Tree">section-Creating-the-Result-Tree in XSLT Specification</a>
036     */
037    public class ProcessorCharacters extends XSLTElementProcessor
038    {
039        static final long serialVersionUID = 8632900007814162650L;
040    
041      /**
042       * Receive notification of the start of the non-text event.  This
043       * is sent to the current processor when any non-text event occurs.
044       *
045       * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
046       */
047      public void startNonText(StylesheetHandler handler) throws org.xml.sax.SAXException
048      {
049        if (this == handler.getCurrentProcessor())
050        {
051          handler.popProcessor();
052        }
053    
054        int nChars = m_accumulator.length();
055    
056        if ((nChars > 0)
057                && ((null != m_xslTextElement)
058                    ||!XMLCharacterRecognizer.isWhiteSpace(m_accumulator)) 
059                    || handler.isSpacePreserve())
060        {
061          ElemTextLiteral elem = new ElemTextLiteral();
062    
063          elem.setDOMBackPointer(m_firstBackPointer);
064          elem.setLocaterInfo(handler.getLocator());
065          try
066          {
067            elem.setPrefixes(handler.getNamespaceSupport());
068          }
069          catch(TransformerException te)
070          {
071            throw new org.xml.sax.SAXException(te);
072          }
073    
074          boolean doe = (null != m_xslTextElement)
075                        ? m_xslTextElement.getDisableOutputEscaping() : false;
076    
077          elem.setDisableOutputEscaping(doe);
078          elem.setPreserveSpace(true);
079    
080          char[] chars = new char[nChars];
081    
082          m_accumulator.getChars(0, nChars, chars, 0);
083          elem.setChars(chars);
084    
085          ElemTemplateElement parent = handler.getElemTemplateElement();
086    
087          parent.appendChild(elem);
088        }
089    
090        m_accumulator.setLength(0);
091        m_firstBackPointer = null;
092      }
093      
094      protected Node m_firstBackPointer = null;
095    
096      /**
097       * Receive notification of character data inside an element.
098       *
099       *
100       * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
101       * @param ch The characters.
102       * @param start The start position in the character array.
103       * @param length The number of characters to use from the
104       *               character array.
105       * @throws org.xml.sax.SAXException Any SAX exception, possibly
106       *            wrapping another exception.
107       * @see org.xml.sax.ContentHandler#characters
108       */
109      public void characters(
110              StylesheetHandler handler, char ch[], int start, int length)
111                throws org.xml.sax.SAXException
112      {
113    
114        m_accumulator.append(ch, start, length);
115        
116        if(null == m_firstBackPointer)
117          m_firstBackPointer = handler.getOriginatingNode();
118    
119        // Catch all events until a non-character event.
120        if (this != handler.getCurrentProcessor())
121          handler.pushProcessor(this);
122      }
123    
124      /**
125       * Receive notification of the end of an element.
126       *
127       * @param handler The calling StylesheetHandler/TemplatesBuilder.
128       * @param uri The Namespace URI, or the empty string if the
129       *        element has no Namespace URI or if Namespace
130       *        processing is not being performed.
131       * @param localName The local name (without prefix), or the
132       *        empty string if Namespace processing is not being
133       *        performed.
134       * @param rawName The raw XML 1.0 name (with prefix), or the
135       *        empty string if raw names are not available.
136       * @see org.apache.xalan.processor.StylesheetHandler#startElement
137       * @see org.apache.xalan.processor.StylesheetHandler#endElement
138       * @see org.xml.sax.ContentHandler#startElement
139       * @see org.xml.sax.ContentHandler#endElement
140       * @see org.xml.sax.Attributes
141       */
142      public void endElement(
143              StylesheetHandler handler, String uri, String localName, String rawName)
144                throws org.xml.sax.SAXException
145      {
146    
147        // Since this has been installed as the current processor, we 
148        // may get and end element event, in which case, we pop and clear 
149        // and then call the real element processor.
150        startNonText(handler);
151        handler.getCurrentProcessor().endElement(handler, uri, localName,
152                                                 rawName);
153        handler.popProcessor();
154      }
155    
156      /**
157       * Accumulate characters, until a non-whitespace event has
158       * occured.
159       */
160      private StringBuffer m_accumulator = new StringBuffer();
161    
162      /**
163       * The xsl:text processor will call this to set a
164       * preserve space state.
165       */
166      private ElemText m_xslTextElement;
167    
168      /**
169       * Set the current setXslTextElement. The xsl:text 
170       * processor will call this to set a preserve space state.
171       *
172       * @param xslTextElement The current xslTextElement that 
173       *                       is preserving state, or null.
174       */
175      void setXslTextElement(ElemText xslTextElement)
176      {
177        m_xslTextElement = xslTextElement;
178      }
179    }