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: XSLTElementProcessor.java 469688 2006-10-31 22:39:43Z minchau $
20 */
21package org.apache.xalan.processor;
22
23import java.util.ArrayList;
24import java.util.List;
25import java.util.Vector;
26
27import javax.xml.transform.TransformerException;
28
29import org.apache.xalan.res.XSLMessages;
30import org.apache.xalan.res.XSLTErrorResources;
31import org.apache.xalan.templates.ElemTemplateElement;
32import org.apache.xml.utils.IntStack;
33import org.xml.sax.Attributes;
34import org.xml.sax.InputSource;
35import org.xml.sax.helpers.AttributesImpl;
36
37/**
38 * This class acts as the superclass for all stylesheet element
39 * processors, and deals with things that are common to all elements.
40 * @see <a href="http://www.w3.org/TR/xslt#dtd">XSLT DTD</a>
41 */
42public class XSLTElementProcessor extends ElemTemplateElement
43{
44    static final long serialVersionUID = 5597421564955304421L;
45
46  /**
47   * Construct a processor for top-level elements.
48   * @see <a href="http://www.w3.org/TR/xslt#dtd">XSLT DTD</a>
49   */
50  XSLTElementProcessor(){}
51
52	private IntStack m_savedLastOrder;
53
54  /**
55   * The element definition that this processor conforms to.
56   */
57  private XSLTElementDef m_elemDef;
58
59  /**
60   * Get the element definition that belongs to this element.
61   *
62   * @return The element definition object that produced and constrains this element.
63   */
64  XSLTElementDef getElemDef()
65  {
66    return m_elemDef;
67  }
68
69  /**
70   * Set the element definition that belongs to this element.
71   *
72   * @param def The element definition object that produced and constrains this element.
73   */
74  void setElemDef(XSLTElementDef def)
75  {
76    m_elemDef = def;
77  }
78
79  /**
80   * Resolve an external entity.
81   *
82   *
83   * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
84   * @param publicId The public identifer, or null if none is
85   *                 available.
86   * @param systemId The system identifier provided in the XML
87   *                 document.
88   * @return The new input source, or null to require the
89   *         default behaviour.
90   */
91  public InputSource resolveEntity(
92          StylesheetHandler handler, String publicId, String systemId)
93            throws org.xml.sax.SAXException
94  {
95    return null;
96  }
97
98  /**
99   * Receive notification of a notation declaration.
100   *
101   *
102   * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
103   * @param name The notation name.
104   * @param publicId The notation public identifier, or null if not
105   *                 available.
106   * @param systemId The notation system identifier.
107   * @see org.xml.sax.DTDHandler#notationDecl
108   */
109  public void notationDecl(StylesheetHandler handler, String name,
110                           String publicId, String systemId)
111  {
112
113    // no op
114  }
115
116  /**
117   * Receive notification of an unparsed entity declaration.
118   *
119   *
120   * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
121   * @param name The entity name.
122   * @param publicId The entity public identifier, or null if not
123   *                 available.
124   * @param systemId The entity system identifier.
125   * @param notationName The name of the associated notation.
126   * @see org.xml.sax.DTDHandler#unparsedEntityDecl
127   */
128  public void unparsedEntityDecl(StylesheetHandler handler, String name,
129                                 String publicId, String systemId,
130                                 String notationName)
131  {
132
133    // no op
134  }
135
136  /**
137   * Receive notification of the start of the non-text event.  This
138   * is sent to the current processor when any non-text event occurs.
139   *
140   * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
141   */
142  public void startNonText(StylesheetHandler handler) throws org.xml.sax.SAXException
143  {
144
145    // no op
146  }
147
148  /**
149   * Receive notification of the start of an element.
150   *
151   * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
152   * @param uri The Namespace URI, or an empty string.
153   * @param localName The local name (without prefix), or empty string if not namespace processing.
154   * @param rawName The qualified name (with prefix).
155   * @param attributes The specified or defaulted attributes.
156   */
157  public void startElement(
158          StylesheetHandler handler, String uri, String localName, String rawName, Attributes attributes)
159            throws org.xml.sax.SAXException
160  {
161
162    if (m_savedLastOrder == null)
163				m_savedLastOrder = new IntStack();
164			m_savedLastOrder.push(getElemDef().getLastOrder());
165			getElemDef().setLastOrder(-1);
166  }
167
168  /**
169   * Receive notification of the end of an element.
170   *
171   * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
172   * @param uri The Namespace URI, or an empty string.
173   * @param localName The local name (without prefix), or empty string if not namespace processing.
174   * @param rawName The qualified name (with prefix).
175   */
176  public void endElement(
177          StylesheetHandler handler, String uri, String localName, String rawName)
178            throws org.xml.sax.SAXException
179  {
180		if (m_savedLastOrder != null && !m_savedLastOrder.empty())
181			getElemDef().setLastOrder(m_savedLastOrder.pop());
182
183		if (!getElemDef().getRequiredFound())
184			handler.error(XSLTErrorResources.ER_REQUIRED_ELEM_NOT_FOUND, new Object[]{getElemDef().getRequiredElem()}, null);
185  }
186
187  /**
188   * Receive notification of character data inside an element.
189   *
190   *
191   * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
192   * @param ch The characters.
193   * @param start The start position in the character array.
194   * @param length The number of characters to use from the
195   *               character array.
196   */
197  public void characters(
198          StylesheetHandler handler, char ch[], int start, int length)
199            throws org.xml.sax.SAXException
200  {
201    handler.error(XSLTErrorResources.ER_CHARS_NOT_ALLOWED, null, null);//"Characters are not allowed at this point in the document!",
202                  //null);
203  }
204
205  /**
206   * Receive notification of ignorable whitespace in element content.
207   *
208   *
209   * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
210   * @param ch The whitespace characters.
211   * @param start The start position in the character array.
212   * @param length The number of characters to use from the
213   *               character array.
214   */
215  public void ignorableWhitespace(
216          StylesheetHandler handler, char ch[], int start, int length)
217            throws org.xml.sax.SAXException
218  {
219
220    // no op
221  }
222
223  /**
224   * Receive notification of a processing instruction.
225   *
226   *
227   * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
228   * @param target The processing instruction target.
229   * @param data The processing instruction data, or null if
230   *             none is supplied.
231   */
232  public void processingInstruction(
233          StylesheetHandler handler, String target, String data)
234            throws org.xml.sax.SAXException
235  {
236
237    // no op
238  }
239
240  /**
241   * Receive notification of a skipped entity.
242   *
243   *
244   * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
245   * @param name The name of the skipped entity.
246   */
247  public void skippedEntity(StylesheetHandler handler, String name)
248          throws org.xml.sax.SAXException
249  {
250
251    // no op
252  }
253
254  /**
255   * Set the properties of an object from the given attribute list.
256   * @param handler The stylesheet's Content handler, needed for
257   *                error reporting.
258   * @param rawName The raw name of the owner element, needed for
259   *                error reporting.
260   * @param attributes The list of attributes.
261   * @param target The target element where the properties will be set.
262   */
263  void setPropertiesFromAttributes(
264          StylesheetHandler handler, String rawName, Attributes attributes,
265          ElemTemplateElement target)
266            throws org.xml.sax.SAXException
267  {
268    setPropertiesFromAttributes(handler, rawName, attributes, target, true);
269  }
270
271  /**
272   * Set the properties of an object from the given attribute list.
273   * @param handler The stylesheet's Content handler, needed for
274   *                error reporting.
275   * @param rawName The raw name of the owner element, needed for
276   *                error reporting.
277   * @param attributes The list of attributes.
278   * @param target The target element where the properties will be set.
279   * @param throwError True if it should throw an error if an
280   * attribute is not defined.
281   * @return the attributes not allowed on this element.
282   *
283   * @throws TransformerException
284   */
285  Attributes setPropertiesFromAttributes(
286          StylesheetHandler handler, String rawName, Attributes attributes,
287          ElemTemplateElement target, boolean throwError)
288            throws org.xml.sax.SAXException
289  {
290
291    XSLTElementDef def = getElemDef();
292    AttributesImpl undefines = null;
293    boolean isCompatibleMode = ((null != handler.getStylesheet()
294                                 && handler.getStylesheet().getCompatibleMode())
295                                || !throwError);
296    if (isCompatibleMode)
297      undefines = new AttributesImpl();
298
299
300    // Keep track of which XSLTAttributeDefs have been processed, so
301    // I can see which default values need to be set.
302    List processedDefs = new ArrayList();
303
304    // Keep track of XSLTAttributeDefs that were invalid
305    List errorDefs = new ArrayList();
306    int nAttrs = attributes.getLength();
307
308    for (int i = 0; i < nAttrs; i++)
309    {
310      String attrUri = attributes.getURI(i);
311      // Hack for Crimson.  -sb
312      if((null != attrUri) && (attrUri.length() == 0)
313                           && (attributes.getQName(i).startsWith("xmlns:") ||
314                               attributes.getQName(i).equals("xmlns")))
315      {
316        attrUri = org.apache.xalan.templates.Constants.S_XMLNAMESPACEURI;
317      }
318      String attrLocalName = attributes.getLocalName(i);
319      XSLTAttributeDef attrDef = def.getAttributeDef(attrUri, attrLocalName);
320
321      if (null == attrDef)
322      {
323        if (!isCompatibleMode)
324        {
325
326          // Then barf, because this element does not allow this attribute.
327          handler.error(XSLTErrorResources.ER_ATTR_NOT_ALLOWED, new Object[]{attributes.getQName(i), rawName}, null);//"\""+attributes.getQName(i)+"\""
328                        //+ " attribute is not allowed on the " + rawName
329                       // + " element!", null);
330        }
331        else
332        {
333          undefines.addAttribute(attrUri, attrLocalName,
334                                 attributes.getQName(i),
335                                 attributes.getType(i),
336                                 attributes.getValue(i));
337        }
338      }
339      else
340      {
341        // Can we switch the order here:
342
343        boolean success = attrDef.setAttrValue(handler, attrUri, attrLocalName,
344                             attributes.getQName(i), attributes.getValue(i),
345                             target);
346
347        // Now we only add the element if it passed a validation check
348        if (success)
349            processedDefs.add(attrDef);
350        else
351            errorDefs.add(attrDef);
352      }
353    }
354
355    XSLTAttributeDef[] attrDefs = def.getAttributes();
356    int nAttrDefs = attrDefs.length;
357
358    for (int i = 0; i < nAttrDefs; i++)
359    {
360      XSLTAttributeDef attrDef = attrDefs[i];
361      String defVal = attrDef.getDefault();
362
363      if (null != defVal)
364      {
365        if (!processedDefs.contains(attrDef))
366        {
367          attrDef.setDefAttrValue(handler, target);
368        }
369      }
370
371      if (attrDef.getRequired())
372      {
373        if ((!processedDefs.contains(attrDef)) && (!errorDefs.contains(attrDef)))
374          handler.error(
375            XSLMessages.createMessage(
376              XSLTErrorResources.ER_REQUIRES_ATTRIB, new Object[]{ rawName,
377                                                                   attrDef.getName() }), null);
378      }
379    }
380
381    return undefines;
382  }
383}
384