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: ProcessorExsltFunction.java 468640 2006-10-28 06:53:53Z minchau $
20 */
21package org.apache.xalan.processor;
22
23import org.apache.xalan.templates.ElemApplyImport;
24import org.apache.xalan.templates.ElemApplyTemplates;
25import org.apache.xalan.templates.ElemAttribute;
26import org.apache.xalan.templates.ElemCallTemplate;
27import org.apache.xalan.templates.ElemComment;
28import org.apache.xalan.templates.ElemCopy;
29import org.apache.xalan.templates.ElemCopyOf;
30import org.apache.xalan.templates.ElemElement;
31import org.apache.xalan.templates.ElemExsltFuncResult;
32import org.apache.xalan.templates.ElemExsltFunction;
33import org.apache.xalan.templates.ElemFallback;
34import org.apache.xalan.templates.ElemLiteralResult;
35import org.apache.xalan.templates.ElemMessage;
36import org.apache.xalan.templates.ElemNumber;
37import org.apache.xalan.templates.ElemPI;
38import org.apache.xalan.templates.ElemParam;
39import org.apache.xalan.templates.ElemTemplate;
40import org.apache.xalan.templates.ElemTemplateElement;
41import org.apache.xalan.templates.ElemText;
42import org.apache.xalan.templates.ElemTextLiteral;
43import org.apache.xalan.templates.ElemValueOf;
44import org.apache.xalan.templates.ElemVariable;
45import org.apache.xalan.templates.Stylesheet;
46import org.xml.sax.Attributes;
47import org.xml.sax.SAXException;
48
49
50/**
51 * This class processes parse events for an exslt func:function element.
52 * @xsl.usage internal
53 */
54public class ProcessorExsltFunction extends ProcessorTemplateElem
55{
56    static final long serialVersionUID = 2411427965578315332L;
57  /**
58   * Start an ElemExsltFunction. Verify that it is top level and that it has a name attribute with a
59   * namespace.
60   */
61  public void startElement(
62          StylesheetHandler handler, String uri, String localName, String rawName, Attributes attributes)
63            throws SAXException
64  {
65    //System.out.println("ProcessorFunction.startElement()");
66    String msg = "";
67    if (!(handler.getElemTemplateElement() instanceof Stylesheet))
68    {
69      msg = "func:function element must be top level.";
70      handler.error(msg, new SAXException(msg));
71    }
72    super.startElement(handler, uri, localName, rawName, attributes);
73
74    String val = attributes.getValue("name");
75    int indexOfColon = val.indexOf(":");
76    if (indexOfColon > 0)
77    {
78      //String prefix = val.substring(0, indexOfColon);
79      //String localVal = val.substring(indexOfColon + 1);
80      //String ns = handler.getNamespaceSupport().getURI(prefix);
81      //if (ns.length() > 0)
82      //  System.out.println("fullfuncname " + ns + localVal);
83    }
84    else
85    {
86      msg = "func:function name must have namespace";
87      handler.error(msg, new SAXException(msg));
88    }
89  }
90
91  /**
92   * Must include; super doesn't suffice!
93   */
94  protected void appendAndPush(
95          StylesheetHandler handler, ElemTemplateElement elem)
96            throws SAXException
97  {
98    //System.out.println("ProcessorFunction appendAndPush()" + elem);
99    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}
190