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: ProcessorLRE.java 475981 2006-11-16 23:35:53Z minchau $
20 */
21package org.apache.xalan.processor;
22
23import java.util.List;
24
25import javax.xml.transform.TransformerConfigurationException;
26import javax.xml.transform.TransformerException;
27
28import org.apache.xalan.res.XSLMessages;
29import org.apache.xalan.res.XSLTErrorResources;
30import org.apache.xalan.templates.Constants;
31import org.apache.xalan.templates.ElemExtensionCall;
32import org.apache.xalan.templates.ElemLiteralResult;
33import org.apache.xalan.templates.ElemTemplate;
34import org.apache.xalan.templates.ElemTemplateElement;
35import org.apache.xalan.templates.Stylesheet;
36import org.apache.xalan.templates.StylesheetRoot;
37import org.apache.xalan.templates.XMLNSDecl;
38import org.apache.xml.utils.SAXSourceLocator;
39import org.apache.xpath.XPath;
40
41import org.xml.sax.Attributes;
42import org.xml.sax.Locator;
43import org.xml.sax.helpers.AttributesImpl;
44
45/**
46 * Processes an XSLT literal-result-element, or something that looks
47 * like one.  The actual {@link org.apache.xalan.templates.ElemTemplateElement}
48 * produced may be a {@link org.apache.xalan.templates.ElemLiteralResult},
49 * a {@link org.apache.xalan.templates.StylesheetRoot}, or a
50 * {@link org.apache.xalan.templates.ElemExtensionCall}.
51 *
52 * @see <a href="http://www.w3.org/TR/xslt#literal-result-element">literal-result-element in XSLT Specification</a>
53 * @see org.apache.xalan.templates.ElemLiteralResult
54 * @xsl.usage internal
55 */
56public class ProcessorLRE extends ProcessorTemplateElem
57{
58    static final long serialVersionUID = -1490218021772101404L;
59  /**
60   * Receive notification of the start of an element.
61   *
62   * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
63   * @param uri The Namespace URI, or an empty string.
64   * @param localName The local name (without prefix), or empty string if not namespace processing.
65   * @param rawName The qualified name (with prefix).
66   * @param attributes The specified or defaulted attributes.
67   */
68  public void startElement(
69          StylesheetHandler handler, String uri, String localName, String rawName, Attributes attributes)
70            throws org.xml.sax.SAXException
71  {
72
73    try
74    {
75      ElemTemplateElement p = handler.getElemTemplateElement();
76      boolean excludeXSLDecl = false;
77      boolean isLREAsStyleSheet = false;
78
79      if (null == p)
80      {
81
82        // Literal Result Template as stylesheet.
83        XSLTElementProcessor lreProcessor = handler.popProcessor();
84        XSLTElementProcessor stylesheetProcessor =
85                                                  handler.getProcessorFor(Constants.S_XSLNAMESPACEURL, "stylesheet",
86                                                                          "xsl:stylesheet");
87
88        handler.pushProcessor(lreProcessor);
89
90        Stylesheet stylesheet;
91        try
92        {
93          stylesheet = getStylesheetRoot(handler);
94        }
95        catch(TransformerConfigurationException tfe)
96        {
97          throw new TransformerException(tfe);
98        }
99
100        // stylesheet.setDOMBackPointer(handler.getOriginatingNode());
101        // ***** Note that we're assigning an empty locator. Is this necessary?
102        SAXSourceLocator slocator = new SAXSourceLocator();
103        Locator locator = handler.getLocator();
104        if(null != locator)
105        {
106          slocator.setLineNumber(locator.getLineNumber());
107          slocator.setColumnNumber(locator.getColumnNumber());
108          slocator.setPublicId(locator.getPublicId());
109          slocator.setSystemId(locator.getSystemId());
110        }
111        stylesheet.setLocaterInfo(slocator);
112        stylesheet.setPrefixes(handler.getNamespaceSupport());
113        handler.pushStylesheet(stylesheet);
114
115        isLREAsStyleSheet = true;
116
117        AttributesImpl stylesheetAttrs = new AttributesImpl();
118        AttributesImpl lreAttrs = new AttributesImpl();
119        int n = attributes.getLength();
120
121        for (int i = 0; i < n; i++)
122        {
123          String attrLocalName = attributes.getLocalName(i);
124          String attrUri = attributes.getURI(i);
125          String value = attributes.getValue(i);
126
127          if ((null != attrUri) && attrUri.equals(Constants.S_XSLNAMESPACEURL))
128          {
129            stylesheetAttrs.addAttribute(null, attrLocalName, attrLocalName,
130                                         attributes.getType(i),
131                                         attributes.getValue(i));
132          }
133          else if ((attrLocalName.startsWith("xmlns:") || attrLocalName.equals(
134                                                                               "xmlns")) && value.equals(Constants.S_XSLNAMESPACEURL))
135          {
136
137            // ignore
138          }
139          else
140          {
141            lreAttrs.addAttribute(attrUri, attrLocalName,
142                                  attributes.getQName(i),
143                                  attributes.getType(i),
144                                  attributes.getValue(i));
145          }
146        }
147
148        attributes = lreAttrs;
149
150        // Set properties from the attributes, but don't throw
151        // an error if there is an attribute defined that is not
152        // allowed on a stylesheet.
153				try{
154        stylesheetProcessor.setPropertiesFromAttributes(handler, "stylesheet",
155                                                        stylesheetAttrs, stylesheet);
156				}
157				catch (Exception e)
158				{
159					// This is pretty ugly, but it will have to do for now.
160					// This is just trying to append some text specifying that
161					// this error came from a missing or invalid XSLT namespace
162					// declaration.
163					// If someone comes up with a better solution, please feel
164					// free to contribute it. -mm
165
166					if (stylesheet.getDeclaredPrefixes() == null ||
167						!declaredXSLNS(stylesheet))
168					{
169						throw new org.xml.sax.SAXException(XSLMessages.createWarning(XSLTErrorResources.WG_OLD_XSLT_NS, null));
170					}
171					else
172                    {
173						throw new org.xml.sax.SAXException(e);
174                    }
175				}
176        handler.pushElemTemplateElement(stylesheet);
177
178        ElemTemplate template = new ElemTemplate();
179        if (slocator != null)
180            template.setLocaterInfo(slocator);
181
182        appendAndPush(handler, template);
183
184        XPath rootMatch = new XPath("/", stylesheet, stylesheet, XPath.MATCH,
185             handler.getStylesheetProcessor().getErrorListener());
186
187        template.setMatch(rootMatch);
188
189        // template.setDOMBackPointer(handler.getOriginatingNode());
190        stylesheet.setTemplate(template);
191
192        p = handler.getElemTemplateElement();
193        excludeXSLDecl = true;
194      }
195
196      XSLTElementDef def = getElemDef();
197      Class classObject = def.getClassObject();
198      boolean isExtension = false;
199      boolean isComponentDecl = false;
200      boolean isUnknownTopLevel = false;
201
202      while (null != p)
203      {
204
205        // System.out.println("Checking: "+p);
206        if (p instanceof ElemLiteralResult)
207        {
208          ElemLiteralResult parentElem = (ElemLiteralResult) p;
209
210          isExtension = parentElem.containsExtensionElementURI(uri);
211        }
212        else if (p instanceof Stylesheet)
213        {
214          Stylesheet parentElem = (Stylesheet) p;
215
216          isExtension = parentElem.containsExtensionElementURI(uri);
217
218          if ((false == isExtension) && (null != uri)
219              && (uri.equals(Constants.S_BUILTIN_EXTENSIONS_URL)
220                  || uri.equals(Constants.S_BUILTIN_OLD_EXTENSIONS_URL)))
221          {
222            isComponentDecl = true;
223          }
224          else
225          {
226            isUnknownTopLevel = true;
227          }
228        }
229
230        if (isExtension)
231          break;
232
233        p = p.getParentElem();
234      }
235
236      ElemTemplateElement elem = null;
237
238      try
239      {
240        if (isExtension)
241        {
242
243          // System.out.println("Creating extension(1): "+uri);
244          elem = new ElemExtensionCall();
245        }
246        else if (isComponentDecl)
247        {
248          elem = (ElemTemplateElement) classObject.newInstance();
249        }
250        else if (isUnknownTopLevel)
251        {
252
253          // TBD: Investigate, not sure about this.  -sb
254          elem = (ElemTemplateElement) classObject.newInstance();
255        }
256        else
257        {
258          elem = (ElemTemplateElement) classObject.newInstance();
259        }
260
261        elem.setDOMBackPointer(handler.getOriginatingNode());
262        elem.setLocaterInfo(handler.getLocator());
263        elem.setPrefixes(handler.getNamespaceSupport(), excludeXSLDecl);
264
265        if (elem instanceof ElemLiteralResult)
266        {
267          ((ElemLiteralResult) elem).setNamespace(uri);
268          ((ElemLiteralResult) elem).setLocalName(localName);
269          ((ElemLiteralResult) elem).setRawName(rawName);
270          ((ElemLiteralResult) elem).setIsLiteralResultAsStylesheet(
271                                                                    isLREAsStyleSheet);
272        }
273      }
274      catch (InstantiationException ie)
275      {
276        handler.error(XSLTErrorResources.ER_FAILED_CREATING_ELEMLITRSLT, null, ie);//"Failed creating ElemLiteralResult instance!", ie);
277      }
278      catch (IllegalAccessException iae)
279      {
280        handler.error(XSLTErrorResources.ER_FAILED_CREATING_ELEMLITRSLT, null, iae);//"Failed creating ElemLiteralResult instance!", iae);
281      }
282
283      setPropertiesFromAttributes(handler, rawName, attributes, elem);
284
285      // bit of a hack here...
286      if (!isExtension && (elem instanceof ElemLiteralResult))
287      {
288        isExtension =
289                     ((ElemLiteralResult) elem).containsExtensionElementURI(uri);
290
291        if (isExtension)
292        {
293
294          // System.out.println("Creating extension(2): "+uri);
295          elem = new ElemExtensionCall();
296
297          elem.setLocaterInfo(handler.getLocator());
298          elem.setPrefixes(handler.getNamespaceSupport());
299          ((ElemLiteralResult) elem).setNamespace(uri);
300          ((ElemLiteralResult) elem).setLocalName(localName);
301          ((ElemLiteralResult) elem).setRawName(rawName);
302          setPropertiesFromAttributes(handler, rawName, attributes, elem);
303        }
304      }
305
306      appendAndPush(handler, elem);
307    }
308    catch(TransformerException te)
309    {
310      throw new org.xml.sax.SAXException(te);
311    }
312  }
313
314  /**
315   * This method could be over-ridden by a class that extends this class.
316   * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
317   * @return an object that represents the stylesheet element.
318   */
319  protected Stylesheet getStylesheetRoot(StylesheetHandler handler) throws TransformerConfigurationException
320  {
321    StylesheetRoot stylesheet;
322    stylesheet = new StylesheetRoot(handler.getSchema(), handler.getStylesheetProcessor().getErrorListener());
323    if (handler.getStylesheetProcessor().isSecureProcessing())
324      stylesheet.setSecureProcessing(true);
325
326    return stylesheet;
327  }
328
329
330/**
331   * Receive notification of the end of an element.
332   *
333   * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
334   * @param uri The Namespace URI, or an empty string.
335   * @param localName The local name (without prefix), or empty string if not namespace processing.
336   * @param rawName The qualified name (with prefix).
337   */
338  public void endElement(
339          StylesheetHandler handler, String uri, String localName, String rawName)
340            throws org.xml.sax.SAXException
341  {
342
343    ElemTemplateElement elem = handler.getElemTemplateElement();
344
345    if (elem instanceof ElemLiteralResult)
346    {
347      if (((ElemLiteralResult) elem).getIsLiteralResultAsStylesheet())
348      {
349        handler.popStylesheet();
350      }
351    }
352
353    super.endElement(handler, uri, localName, rawName);
354  }
355
356	private boolean declaredXSLNS(Stylesheet stylesheet)
357	{
358		List declaredPrefixes = stylesheet.getDeclaredPrefixes();
359		int n = declaredPrefixes.size();
360
361		for (int i = 0; i < n; i++)
362		{
363			XMLNSDecl decl = (XMLNSDecl) declaredPrefixes.get(i);
364			if(decl.getURI().equals(Constants.S_XSLNAMESPACEURL))
365				return true;
366		}
367		return false;
368	}
369}
370