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 }