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: ProcessorExsltFunction.java 468640 2006-10-28 06:53:53Z minchau $
020     */
021    package org.apache.xalan.processor;
022    
023    import org.apache.xalan.templates.ElemApplyImport;
024    import org.apache.xalan.templates.ElemApplyTemplates;
025    import org.apache.xalan.templates.ElemAttribute;
026    import org.apache.xalan.templates.ElemCallTemplate;
027    import org.apache.xalan.templates.ElemComment;
028    import org.apache.xalan.templates.ElemCopy;
029    import org.apache.xalan.templates.ElemCopyOf;
030    import org.apache.xalan.templates.ElemElement;
031    import org.apache.xalan.templates.ElemExsltFuncResult;
032    import org.apache.xalan.templates.ElemExsltFunction;
033    import org.apache.xalan.templates.ElemFallback;
034    import org.apache.xalan.templates.ElemLiteralResult;
035    import org.apache.xalan.templates.ElemMessage;
036    import org.apache.xalan.templates.ElemNumber;
037    import org.apache.xalan.templates.ElemPI;
038    import org.apache.xalan.templates.ElemParam;
039    import org.apache.xalan.templates.ElemTemplate;
040    import org.apache.xalan.templates.ElemTemplateElement;
041    import org.apache.xalan.templates.ElemText;
042    import org.apache.xalan.templates.ElemTextLiteral;
043    import org.apache.xalan.templates.ElemValueOf;
044    import org.apache.xalan.templates.ElemVariable;
045    import org.apache.xalan.templates.Stylesheet;
046    import org.xml.sax.Attributes;
047    import org.xml.sax.SAXException;
048    
049    
050    /**
051     * This class processes parse events for an exslt func:function element.
052     * @xsl.usage internal
053     */
054    public class ProcessorExsltFunction extends ProcessorTemplateElem
055    {
056        static final long serialVersionUID = 2411427965578315332L;
057      /**
058       * Start an ElemExsltFunction. Verify that it is top level and that it has a name attribute with a
059       * namespace.
060       */
061      public void startElement(
062              StylesheetHandler handler, String uri, String localName, String rawName, Attributes attributes)
063                throws SAXException
064      {
065        //System.out.println("ProcessorFunction.startElement()");
066        String msg = "";
067        if (!(handler.getElemTemplateElement() instanceof Stylesheet))
068        {
069          msg = "func:function element must be top level.";
070          handler.error(msg, new SAXException(msg));
071        }
072        super.startElement(handler, uri, localName, rawName, attributes);
073           
074        String val = attributes.getValue("name");
075        int indexOfColon = val.indexOf(":");
076        if (indexOfColon > 0)
077        {
078          //String prefix = val.substring(0, indexOfColon);
079          //String localVal = val.substring(indexOfColon + 1);
080          //String ns = handler.getNamespaceSupport().getURI(prefix);
081          //if (ns.length() > 0)
082          //  System.out.println("fullfuncname " + ns + localVal);
083        }
084        else
085        {
086          msg = "func:function name must have namespace";
087          handler.error(msg, new SAXException(msg));
088        }
089      }
090      
091      /**
092       * Must include; super doesn't suffice!
093       */
094      protected void appendAndPush(
095              StylesheetHandler handler, ElemTemplateElement elem)
096                throws SAXException
097      {
098        //System.out.println("ProcessorFunction appendAndPush()" + elem);
099        super.appendAndPush(handler, elem);
100        //System.out.println("originating node " + handler.getOriginatingNode());
101        elem.setDOMBackPointer(handler.getOriginatingNode());
102        handler.getStylesheet().setTemplate((ElemTemplate) elem);
103      }
104        
105      /**
106       * End an ElemExsltFunction, and verify its validity.
107       */
108      public void endElement(
109              StylesheetHandler handler, String uri, String localName, String rawName)
110                throws SAXException
111      {
112       ElemTemplateElement function = handler.getElemTemplateElement();
113       validate(function, handler); // may throw exception
114       super.endElement(handler, uri, localName, rawName);   
115      }
116      
117      /**
118       * Non-recursive traversal of FunctionElement tree based on TreeWalker to verify that
119       * there are no literal result elements except within a func:result element and that
120       * the func:result element does not contain any following siblings except xsl:fallback.
121       */
122      public void validate(ElemTemplateElement elem, StylesheetHandler handler)
123        throws SAXException
124      {
125        String msg = "";
126        while (elem != null)
127        { 
128          //System.out.println("elem " + elem);
129          if (elem instanceof ElemExsltFuncResult 
130              && elem.getNextSiblingElem() != null 
131              && !(elem.getNextSiblingElem() instanceof ElemFallback))
132          {
133            msg = "func:result has an illegal following sibling (only xsl:fallback allowed)";
134            handler.error(msg, new SAXException(msg));
135          }
136          
137          if((elem instanceof ElemApplyImport
138             || elem instanceof ElemApplyTemplates
139             || elem instanceof ElemAttribute
140             || elem instanceof ElemCallTemplate
141             || elem instanceof ElemComment
142             || elem instanceof ElemCopy
143             || elem instanceof ElemCopyOf
144             || elem instanceof ElemElement
145             || elem instanceof ElemLiteralResult
146             || elem instanceof ElemNumber
147             || elem instanceof ElemPI
148             || elem instanceof ElemText
149             || elem instanceof ElemTextLiteral
150             || elem instanceof ElemValueOf)
151            && !(ancestorIsOk(elem)))
152          {
153            msg ="misplaced literal result in a func:function container.";
154            handler.error(msg, new SAXException(msg));
155          }
156          ElemTemplateElement nextElem = elem.getFirstChildElem();
157          while (nextElem == null)
158          {
159            nextElem = elem.getNextSiblingElem();
160            if (nextElem == null)
161              elem = elem.getParentElem();
162            if (elem == null || elem instanceof ElemExsltFunction)
163              return; // ok
164          }  
165          elem = nextElem;
166        }
167      }
168      
169      /**
170       * Verify that a literal result belongs to a result element, a variable, 
171       * or a parameter.
172       */
173      
174      boolean ancestorIsOk(ElemTemplateElement child)
175      {
176        while (child.getParentElem() != null && !(child.getParentElem() instanceof ElemExsltFunction))
177        {
178          ElemTemplateElement parent = child.getParentElem();
179          if (parent instanceof ElemExsltFuncResult 
180              || parent instanceof ElemVariable
181              || parent instanceof ElemParam
182              || parent instanceof ElemMessage)
183            return true;
184          child = parent;      
185        }
186        return false;
187      }
188      
189    }