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: ExtensionHandlerExsltFunction.java 469672 2006-10-31 21:56:19Z minchau $
020 */
021 package org.apache.xalan.extensions;
022
023 import java.io.IOException;
024 import java.util.Vector;
025
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.ElemExsltFuncResult;
032 import org.apache.xalan.templates.ElemExsltFunction;
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.transformer.TransformerImpl;
038 import org.apache.xml.utils.QName;
039 import org.apache.xpath.ExpressionNode;
040 import org.apache.xpath.XPathContext;
041 import org.apache.xpath.functions.FuncExtFunction;
042 import org.apache.xpath.objects.XObject;
043 import org.apache.xpath.objects.XString;
044
045 /**
046 * Execute EXSLT functions, determine the availability of EXSLT functions, and the
047 * availability of an EXSLT result element.
048 */
049 public class ExtensionHandlerExsltFunction extends ExtensionHandler
050 {
051 private String m_namespace;
052 private StylesheetRoot m_stylesheet;
053 private static final QName RESULTQNAME =
054 new QName(Constants.S_EXSLT_FUNCTIONS_URL,
055 Constants.EXSLT_ELEMNAME_FUNCRESULT_STRING);
056 /**
057 * Constructor called from ElemExsltFunction runtimeInit().
058 */
059 public ExtensionHandlerExsltFunction(String ns, StylesheetRoot stylesheet)
060 {
061 super(ns, "xml"); // required by ExtensionHandler interface.
062 m_namespace = ns;
063 m_stylesheet = stylesheet;
064 }
065
066 /**
067 * Required by ExtensionHandler (an abstract method). No-op.
068 */
069 public void processElement(
070 String localPart, ElemTemplateElement element, TransformerImpl transformer,
071 Stylesheet stylesheetTree, Object methodKey) throws TransformerException, IOException
072 {}
073
074 /**
075 * Get the ElemExsltFunction element associated with the
076 * function.
077 *
078 * @param funcName Local name of the function.
079 * @return the ElemExsltFunction element associated with
080 * the function, null if none exists.
081 */
082 public ElemExsltFunction getFunction(String funcName)
083 {
084 QName qname = new QName(m_namespace, funcName);
085 ElemTemplate templ = m_stylesheet.getTemplateComposed(qname);
086 if (templ != null && templ instanceof ElemExsltFunction)
087 return (ElemExsltFunction) templ;
088 else
089 return null;
090 }
091
092
093 /**
094 * Does the EXSLT function exist?
095 *
096 * @param funcName Local name of the function.
097 * @return true if the function exists.
098 */
099 public boolean isFunctionAvailable(String funcName)
100 {
101 return getFunction(funcName)!= null;
102 }
103
104 /** If an element-available() call applies to an EXSLT result element within
105 * an EXSLT function element, return true.
106 *
107 * Note: The EXSLT function element is a template-level element, and
108 * element-available() returns false for it.
109 *
110 * @param elemName name of the element.
111 * @return true if the function is available.
112 */
113 public boolean isElementAvailable(String elemName)
114 {
115 if (!(new QName(m_namespace, elemName).equals(RESULTQNAME)))
116 {
117 return false;
118 }
119 else
120 {
121 ElemTemplateElement elem = m_stylesheet.getFirstChildElem();
122 while (elem != null && elem != m_stylesheet)
123 {
124 if (elem instanceof ElemExsltFuncResult && ancestorIsFunction(elem))
125 return true;
126 ElemTemplateElement nextElem = elem.getFirstChildElem();
127 if (nextElem == null)
128 nextElem = elem.getNextSiblingElem();
129 if (nextElem == null)
130 nextElem = elem.getParentElem();
131 elem = nextElem;
132 }
133 }
134 return false;
135 }
136
137 /**
138 * Determine whether the func:result element is within a func:function element.
139 * If not, it is illegal.
140 */
141 private boolean ancestorIsFunction(ElemTemplateElement child)
142 {
143 while (child.getParentElem() != null
144 && !(child.getParentElem() instanceof StylesheetRoot))
145 {
146 if (child.getParentElem() instanceof ElemExsltFunction)
147 return true;
148 child = child.getParentElem();
149 }
150 return false;
151 }
152
153 /**
154 * Execute the EXSLT function and return the result value.
155 *
156 * @param funcName Name of the EXSLT function.
157 * @param args The arguments of the function call.
158 * @param methodKey Not used.
159 * @param exprContext Used to get the XPathContext.
160 * @return the return value of the function evaluation.
161 * @throws TransformerException
162 */
163 public Object callFunction(
164 String funcName, Vector args, Object methodKey,
165 ExpressionContext exprContext) throws TransformerException
166 {
167 throw new TransformerException("This method should not be called.");
168 }
169
170 /**
171 * Execute the EXSLT function and return the result value.
172 *
173 * @param extFunction The XPath extension function
174 * @param args The arguments of the function call.
175 * @param exprContext The context in which this expression is being executed.
176 * @return the return value of the function evaluation.
177 * @throws TransformerException
178 */
179 public Object callFunction(FuncExtFunction extFunction,
180 Vector args,
181 ExpressionContext exprContext)
182 throws TransformerException
183 {
184 // Find the template which invokes this EXSLT function.
185 ExpressionNode parent = extFunction.exprGetParent();
186 while (parent != null && !(parent instanceof ElemTemplate))
187 {
188 parent = parent.exprGetParent();
189 }
190
191 ElemTemplate callerTemplate = (parent != null) ? (ElemTemplate)parent: null;
192
193 XObject[] methodArgs;
194 methodArgs = new XObject[args.size()];
195 try
196 {
197 for (int i = 0; i < methodArgs.length; i++)
198 {
199 methodArgs[i] = XObject.create(args.get(i));
200 }
201
202 ElemExsltFunction elemFunc = getFunction(extFunction.getFunctionName());
203
204 if (null != elemFunc) {
205 XPathContext context = exprContext.getXPathContext();
206 TransformerImpl transformer = (TransformerImpl)context.getOwnerObject();
207 transformer.pushCurrentFuncResult(null);
208
209 elemFunc.execute(transformer, methodArgs);
210
211 XObject val = (XObject)transformer.popCurrentFuncResult();
212 return (val == null) ? new XString("") // value if no result element.
213 : val;
214 }
215 else {
216 throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_FUNCTION_NOT_FOUND, new Object[] {extFunction.getFunctionName()}));
217 }
218 }
219 catch (TransformerException e)
220 {
221 throw e;
222 }
223 catch (Exception e)
224 {
225 throw new TransformerException(e);
226 }
227 }
228
229 }