001: /*
002: * Copyright 2004,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.bsf.engines.xslt;
018:
019: import java.io.File;
020: import java.io.Reader;
021: import java.io.StringReader;
022: import java.net.URL;
023: import java.util.Vector;
024:
025: import javax.xml.transform.Transformer;
026: import javax.xml.transform.TransformerFactory;
027: import javax.xml.transform.dom.DOMResult;
028: import javax.xml.transform.dom.DOMSource;
029: import javax.xml.transform.stream.StreamSource;
030:
031: import org.apache.bsf.BSFDeclaredBean;
032: import org.apache.bsf.BSFException;
033: import org.apache.bsf.BSFManager;
034: import org.apache.bsf.util.BSFEngineImpl;
035: import org.apache.bsf.util.BSFFunctions;
036: import org.apache.commons.logging.Log;
037: import org.apache.commons.logging.LogFactory;
038: import org.apache.xpath.objects.XObject;
039: import org.w3c.dom.Node;
040:
041: /**
042: * Xerces XSLT interface to BSF. Requires Xalan and Xerces from Apache.
043: *
044: * This integration uses the BSF registry to pass in any src document
045: * and stylesheet base URI that the user may wish to set.
046: *
047: * @author Sanjiva Weerawarana
048: * @author Sam Ruby
049: *
050: * Re-implemented for the Xalan 2 codebase
051: *
052: * @author Victor J. Orlikowski
053: */
054: public class XSLTEngine extends BSFEngineImpl {
055: TransformerFactory tFactory;
056: Transformer transformer;
057:
058: Log logger = LogFactory.getLog(this .getClass().getName());
059:
060: /**
061: * call the named method of the given object.
062: */
063: public Object call(Object object, String method, Object[] args)
064: throws BSFException {
065: throw new BSFException(BSFException.REASON_UNSUPPORTED_FEATURE,
066: "BSF:XSLTEngine can't call methods");
067: }
068:
069: /**
070: * Declare a bean by setting it as a parameter
071: */
072: public void declareBean(BSFDeclaredBean bean) throws BSFException {
073: transformer.setParameter(bean.name, new XObject(bean.bean));
074: }
075:
076: /**
077: * Evaluate an expression. In this case, an expression is assumed
078: * to be a stylesheet of the template style (see the XSLT spec).
079: */
080: public Object eval(String source, int lineNo, int columnNo,
081: Object oscript) throws BSFException {
082: // get the style base URI (the place from where Xerces XSLT will
083: // look for imported/included files and referenced docs): if a
084: // bean named "xslt:styleBaseURI" is registered, then cvt it
085: // to a string and use that. Otherwise use ".", which means the
086: // base is the directory where the process is running from
087: Object sbObj = mgr.lookupBean("xslt:styleBaseURI");
088: String styleBaseURI = (sbObj == null) ? "." : sbObj.toString();
089:
090: // Locate the stylesheet.
091: StreamSource styleSource;
092:
093: styleSource = new StreamSource(new StringReader(oscript
094: .toString()));
095: styleSource.setSystemId(styleBaseURI);
096:
097: try {
098: transformer = tFactory.newTransformer(styleSource);
099: } catch (Exception e) {
100: logger.error("Exception from Xerces XSLT:", e);
101: throw new BSFException(BSFException.REASON_EXECUTION_ERROR,
102: "Exception from Xerces XSLT: " + e, e);
103: }
104:
105: // get the src to work on: if a bean named "xslt:src" is registered
106: // and its a Node, then use it as the source. If its not a Node, then
107: // if its a URL parse it, if not treat it as a file and make a URL and
108: // parse it and go. If no xslt:src is found, use an empty document
109: // (stylesheet is treated as a literal result element stylesheet)
110: Object srcObj = mgr.lookupBean("xslt:src");
111: Object xis = null;
112: if (srcObj != null) {
113: if (srcObj instanceof Node) {
114: xis = new DOMSource((Node) srcObj);
115: } else {
116: try {
117: String mesg = "as anything";
118: if (srcObj instanceof Reader) {
119: xis = new StreamSource((Reader) srcObj);
120: mesg = "as a Reader";
121: } else if (srcObj instanceof File) {
122: xis = new StreamSource((File) srcObj);
123: mesg = "as a file";
124: } else {
125: String srcObjstr = srcObj.toString();
126: xis = new StreamSource(new StringReader(
127: srcObjstr));
128: if (srcObj instanceof URL) {
129: mesg = "as a URL";
130: } else {
131: ((StreamSource) xis).setPublicId(srcObjstr);
132: mesg = "as an XML string";
133: }
134: }
135:
136: if (xis == null) {
137: throw new Exception(
138: "Unable to get input from '" + srcObj
139: + "' " + mesg);
140: }
141: } catch (Exception e) {
142: throw new BSFException(
143: BSFException.REASON_EXECUTION_ERROR,
144: "BSF:XSLTEngine: unable to get "
145: + "input from '" + srcObj
146: + "' as XML", e);
147: }
148: }
149: } else {
150: // create an empty document - real src must come into the
151: // stylesheet using "doc(...)" [see XSLT spec] or the stylesheet
152: // must be of literal result element type
153: xis = new StreamSource();
154: }
155:
156: // set all declared beans as parameters.
157: for (int i = 0; i < declaredBeans.size(); i++) {
158: BSFDeclaredBean b = (BSFDeclaredBean) declaredBeans
159: .elementAt(i);
160: transformer.setParameter(b.name, new XObject(b.bean));
161: }
162:
163: // declare a "bsf" parameter which is the BSF handle so that
164: // the script can do BSF stuff if it wants to
165: transformer.setParameter("bsf", new XObject(new BSFFunctions(
166: mgr, this )));
167:
168: // do it
169: try {
170: DOMResult result = new DOMResult();
171: transformer.transform((StreamSource) xis, result);
172: return new XSLTResultNode(result.getNode());
173: } catch (Exception e) {
174: throw new BSFException(BSFException.REASON_EXECUTION_ERROR,
175: "exception while eval'ing XSLT script" + e, e);
176: }
177: }
178:
179: /**
180: * Initialize the engine.
181: */
182: public void initialize(BSFManager mgr, String lang,
183: Vector declaredBeans) throws BSFException {
184: super .initialize(mgr, lang, declaredBeans);
185:
186: tFactory = TransformerFactory.newInstance();
187: }
188:
189: /**
190: * Undeclare a bean by setting he parameter represeting it to null
191: */
192: public void undeclareBean(BSFDeclaredBean bean) throws BSFException {
193: // Cannot clear only one parameter in Xalan 2, so we set it to null
194: if ((transformer.getParameter(bean.name)) != null) {
195: transformer.setParameter(bean.name, null);
196: }
197: }
198: }
|