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: ProcessorCharacters.java 468640 2006-10-28 06:53:53Z minchau $
20 */
21package org.apache.xalan.processor;
22
23import javax.xml.transform.TransformerException;
24
25import org.apache.xalan.templates.ElemTemplateElement;
26import org.apache.xalan.templates.ElemText;
27import org.apache.xalan.templates.ElemTextLiteral;
28import org.apache.xml.utils.XMLCharacterRecognizer;
29
30import org.w3c.dom.Node;
31
32/**
33 * This class processes character events for a XSLT template element.
34 * @see <a href="http://www.w3.org/TR/xslt#dtd">XSLT DTD</a>
35 * @see <a href="http://www.w3.org/TR/xslt#section-Creating-the-Result-Tree">section-Creating-the-Result-Tree in XSLT Specification</a>
36 */
37public class ProcessorCharacters extends XSLTElementProcessor
38{
39    static final long serialVersionUID = 8632900007814162650L;
40
41  /**
42   * Receive notification of the start of the non-text event.  This
43   * is sent to the current processor when any non-text event occurs.
44   *
45   * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
46   */
47  public void startNonText(StylesheetHandler handler) throws org.xml.sax.SAXException
48  {
49    if (this == handler.getCurrentProcessor())
50    {
51      handler.popProcessor();
52    }
53
54    int nChars = m_accumulator.length();
55
56    if ((nChars > 0)
57            && ((null != m_xslTextElement)
58                ||!XMLCharacterRecognizer.isWhiteSpace(m_accumulator))
59                || handler.isSpacePreserve())
60    {
61      ElemTextLiteral elem = new ElemTextLiteral();
62
63      elem.setDOMBackPointer(m_firstBackPointer);
64      elem.setLocaterInfo(handler.getLocator());
65      try
66      {
67        elem.setPrefixes(handler.getNamespaceSupport());
68      }
69      catch(TransformerException te)
70      {
71        throw new org.xml.sax.SAXException(te);
72      }
73
74      boolean doe = (null != m_xslTextElement)
75                    ? m_xslTextElement.getDisableOutputEscaping() : false;
76
77      elem.setDisableOutputEscaping(doe);
78      elem.setPreserveSpace(true);
79
80      char[] chars = new char[nChars];
81
82      m_accumulator.getChars(0, nChars, chars, 0);
83      elem.setChars(chars);
84
85      ElemTemplateElement parent = handler.getElemTemplateElement();
86
87      parent.appendChild(elem);
88    }
89
90    m_accumulator.setLength(0);
91    m_firstBackPointer = null;
92  }
93
94  protected Node m_firstBackPointer = null;
95
96  /**
97   * Receive notification of character data inside an element.
98   *
99   *
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}
180