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: ProcessorLRE.java 475981 2006-11-16 23:35:53Z minchau $
020     */
021    package org.apache.xalan.processor;
022    
023    import java.util.List;
024    
025    import javax.xml.transform.TransformerConfigurationException;
026    import javax.xml.transform.TransformerException;
027    
028    import org.apache.xalan.res.XSLMessages;
029    import org.apache.xalan.res.XSLTErrorResources;
030    import org.apache.xalan.templates.Constants;
031    import org.apache.xalan.templates.ElemExtensionCall;
032    import org.apache.xalan.templates.ElemLiteralResult;
033    import org.apache.xalan.templates.ElemTemplate;
034    import org.apache.xalan.templates.ElemTemplateElement;
035    import org.apache.xalan.templates.Stylesheet;
036    import org.apache.xalan.templates.StylesheetRoot;
037    import org.apache.xalan.templates.XMLNSDecl;
038    import org.apache.xml.utils.SAXSourceLocator;
039    import org.apache.xpath.XPath;
040    
041    import org.xml.sax.Attributes;
042    import org.xml.sax.Locator;
043    import org.xml.sax.helpers.AttributesImpl;
044    
045    /**
046     * Processes an XSLT literal-result-element, or something that looks 
047     * like one.  The actual {@link org.apache.xalan.templates.ElemTemplateElement}
048     * produced may be a {@link org.apache.xalan.templates.ElemLiteralResult}, 
049     * a {@link org.apache.xalan.templates.StylesheetRoot}, or a 
050     * {@link org.apache.xalan.templates.ElemExtensionCall}.
051     * 
052     * @see <a href="http://www.w3.org/TR/xslt#literal-result-element">literal-result-element in XSLT Specification</a>
053     * @see org.apache.xalan.templates.ElemLiteralResult
054     * @xsl.usage internal
055     */
056    public class ProcessorLRE extends ProcessorTemplateElem
057    {
058        static final long serialVersionUID = -1490218021772101404L;
059      /**
060       * Receive notification of the start of an element.
061       *
062       * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
063       * @param uri The Namespace URI, or an empty string.
064       * @param localName The local name (without prefix), or empty string if not namespace processing.
065       * @param rawName The qualified name (with prefix).
066       * @param attributes The specified or defaulted attributes.
067       */
068      public void startElement(
069              StylesheetHandler handler, String uri, String localName, String rawName, Attributes attributes)
070                throws org.xml.sax.SAXException
071      {
072    
073        try
074        {
075          ElemTemplateElement p = handler.getElemTemplateElement();
076          boolean excludeXSLDecl = false;
077          boolean isLREAsStyleSheet = false;
078    
079          if (null == p)
080          {
081    
082            // Literal Result Template as stylesheet.
083            XSLTElementProcessor lreProcessor = handler.popProcessor();
084            XSLTElementProcessor stylesheetProcessor =
085                                                      handler.getProcessorFor(Constants.S_XSLNAMESPACEURL, "stylesheet",
086                                                                              "xsl:stylesheet");
087    
088            handler.pushProcessor(lreProcessor);
089    
090            Stylesheet stylesheet;
091            try
092            {
093              stylesheet = getStylesheetRoot(handler);
094            }
095            catch(TransformerConfigurationException tfe)
096            {
097              throw new TransformerException(tfe);
098            }
099    
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    }