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: XSLProcessorContext.java 468637 2006-10-28 06:51:02Z minchau $
020 */
021 package org.apache.xalan.extensions;
022
023 import javax.xml.transform.TransformerException;
024
025 import org.apache.xalan.templates.Stylesheet;
026 import org.apache.xalan.transformer.ClonerToResultTree;
027 import org.apache.xalan.transformer.TransformerImpl;
028 import org.apache.xml.dtm.DTM;
029 import org.apache.xml.dtm.DTMAxisIterator;
030 import org.apache.xml.dtm.DTMIterator;
031 import org.apache.xalan.serialize.SerializerUtils;
032 import org.apache.xml.serializer.SerializationHandler;
033 import org.apache.xml.utils.QName;
034 import org.apache.xpath.XPathContext;
035 import org.apache.xpath.axes.DescendantIterator;
036 import org.apache.xpath.axes.OneStepIterator;
037 import org.apache.xpath.objects.XBoolean;
038 import org.apache.xpath.objects.XNodeSet;
039 import org.apache.xpath.objects.XNumber;
040 import org.apache.xpath.objects.XObject;
041 import org.apache.xpath.objects.XRTreeFrag;
042 import org.apache.xpath.objects.XString;
043 import org.w3c.dom.DocumentFragment;
044 import org.w3c.dom.traversal.NodeIterator;
045
046 // import org.apache.xalan.xslt.*;
047
048 /**
049 * Provides transformer context to be passed to an extension element.
050 *
051 * @author Sanjiva Weerawarana (sanjiva@watson.ibm.com)
052 * @xsl.usage general
053 */
054 public class XSLProcessorContext
055 {
056
057 /**
058 * Create a processor context to be passed to an extension.
059 * (Notice it is a package-only constructor).
060 *
061 * @param transformer non-null transformer instance
062 * @param stylesheetTree The owning stylesheet
063 */
064 public XSLProcessorContext(TransformerImpl transformer,
065 Stylesheet stylesheetTree)
066 {
067
068 this.transformer = transformer;
069 this.stylesheetTree = stylesheetTree;
070 // %TBD%
071 org.apache.xpath.XPathContext xctxt = transformer.getXPathContext();
072 this.mode = transformer.getMode();
073 this.sourceNode = xctxt.getCurrentNode();
074 this.sourceTree = xctxt.getDTM(this.sourceNode);
075 }
076
077 /** An instance of a transformer */
078 private TransformerImpl transformer;
079
080 /**
081 * Get the transformer.
082 *
083 * @return the transformer instance for this context
084 */
085 public TransformerImpl getTransformer()
086 {
087 return transformer;
088 }
089
090 /** The owning stylesheet for this context */
091 private Stylesheet stylesheetTree;
092
093 /**
094 * Get the Stylesheet being executed.
095 *
096 * @return the Stylesheet being executed.
097 */
098 public Stylesheet getStylesheet()
099 {
100 return stylesheetTree;
101 }
102
103 /** The root of the source tree being executed. */
104 private org.apache.xml.dtm.DTM sourceTree;
105
106 /**
107 * Get the root of the source tree being executed.
108 *
109 * @return the root of the source tree being executed.
110 */
111 public org.w3c.dom.Node getSourceTree()
112 {
113 return sourceTree.getNode(sourceTree.getDocumentRoot(sourceNode));
114 }
115
116 /** the current context node. */
117 private int sourceNode;
118
119 /**
120 * Get the current context node.
121 *
122 * @return the current context node.
123 */
124 public org.w3c.dom.Node getContextNode()
125 {
126 return sourceTree.getNode(sourceNode);
127 }
128
129 /** the current mode being executed. */
130 private QName mode;
131
132 /**
133 * Get the current mode being executed.
134 *
135 * @return the current mode being executed.
136 */
137 public QName getMode()
138 {
139 return mode;
140 }
141
142 /**
143 * Output an object to the result tree by doing the right conversions.
144 * This is public for access by extensions.
145 *
146 *
147 * @param stylesheetTree The owning stylesheet
148 * @param obj the Java object to output. If its of an X<something> type
149 * then that conversion is done first and then sent out.
150 *
151 * @throws TransformerException
152 * @throws java.io.FileNotFoundException
153 * @throws java.io.IOException
154 * @throws java.net.MalformedURLException
155 */
156 public void outputToResultTree(Stylesheet stylesheetTree, Object obj)
157 throws TransformerException, java.net.MalformedURLException,
158 java.io.FileNotFoundException, java.io.IOException
159 {
160
161 try
162 {
163 SerializationHandler rtreeHandler = transformer.getResultTreeHandler();
164 XPathContext xctxt = transformer.getXPathContext();
165 XObject value;
166
167 // Make the return object into an XObject because it
168 // will be easier below. One of the reasons to do this
169 // is to keep all the conversion functionality in the
170 // XObject classes.
171 if (obj instanceof XObject)
172 {
173 value = (XObject) obj;
174 }
175 else if (obj instanceof String)
176 {
177 value = new XString((String) obj);
178 }
179 else if (obj instanceof Boolean)
180 {
181 value = new XBoolean(((Boolean) obj).booleanValue());
182 }
183 else if (obj instanceof Double)
184 {
185 value = new XNumber(((Double) obj).doubleValue());
186 }
187 else if (obj instanceof DocumentFragment)
188 {
189 int handle = xctxt.getDTMHandleFromNode((DocumentFragment)obj);
190
191 value = new XRTreeFrag(handle, xctxt);
192 }
193 else if (obj instanceof DTM)
194 {
195 DTM dtm = (DTM)obj;
196 DTMIterator iterator = new DescendantIterator();
197 // %%ISSUE%% getDocument may not be valid for DTMs shared by multiple
198 // document trees, eg RTFs. But in that case, we shouldn't be trying
199 // to iterate over the whole DTM; we should be iterating over
200 // dtm.getDocumentRoot(rootNodeHandle), and folks should have told us
201 // this by passing a more appropriate type.
202 iterator.setRoot(dtm.getDocument(), xctxt);
203 value = new XNodeSet(iterator);
204 }
205 else if (obj instanceof DTMAxisIterator)
206 {
207 DTMAxisIterator iter = (DTMAxisIterator)obj;
208 DTMIterator iterator = new OneStepIterator(iter, -1);
209 value = new XNodeSet(iterator);
210 }
211 else if (obj instanceof DTMIterator)
212 {
213 value = new XNodeSet((DTMIterator) obj);
214 }
215 else if (obj instanceof NodeIterator)
216 {
217 value = new XNodeSet(new org.apache.xpath.NodeSetDTM(((NodeIterator)obj), xctxt));
218 }
219 else if (obj instanceof org.w3c.dom.Node)
220 {
221 value =
222 new XNodeSet(xctxt.getDTMHandleFromNode((org.w3c.dom.Node) obj),
223 xctxt.getDTMManager());
224 }
225 else
226 {
227 value = new XString(obj.toString());
228 }
229
230 int type = value.getType();
231 String s;
232
233 switch (type)
234 {
235 case XObject.CLASS_BOOLEAN :
236 case XObject.CLASS_NUMBER :
237 case XObject.CLASS_STRING :
238 s = value.str();
239
240 rtreeHandler.characters(s.toCharArray(), 0, s.length());
241 break;
242
243 case XObject.CLASS_NODESET : // System.out.println(value);
244 DTMIterator nl = value.iter();
245
246 int pos;
247
248 while (DTM.NULL != (pos = nl.nextNode()))
249 {
250 DTM dtm = nl.getDTM(pos);
251 int top = pos;
252
253 while (DTM.NULL != pos)
254 {
255 rtreeHandler.flushPending();
256 ClonerToResultTree.cloneToResultTree(pos, dtm.getNodeType(pos),
257 dtm, rtreeHandler, true);
258
259 int nextNode = dtm.getFirstChild(pos);
260
261 while (DTM.NULL == nextNode)
262 {
263 if (DTM.ELEMENT_NODE == dtm.getNodeType(pos))
264 {
265 rtreeHandler.endElement("", "", dtm.getNodeName(pos));
266 }
267
268 if (top == pos)
269 break;
270
271 nextNode = dtm.getNextSibling(pos);
272
273 if (DTM.NULL == nextNode)
274 {
275 pos = dtm.getParent(pos);
276
277 if (top == pos)
278 {
279 if (DTM.ELEMENT_NODE == dtm.getNodeType(pos))
280 {
281 rtreeHandler.endElement("", "", dtm.getNodeName(pos));
282 }
283
284 nextNode = DTM.NULL;
285
286 break;
287 }
288 }
289 }
290
291 pos = nextNode;
292 }
293 }
294 break;
295 case XObject.CLASS_RTREEFRAG :
296 SerializerUtils.outputResultTreeFragment(
297 rtreeHandler, value, transformer.getXPathContext());
298 // rtreeHandler.outputResultTreeFragment(value,
299 // transformer.getXPathContext());
300 break;
301 }
302 }
303 catch(org.xml.sax.SAXException se)
304 {
305 throw new TransformerException(se);
306 }
307 }
308
309 /**
310 * I need a "Node transformNode (Node)" method somewhere that the
311 * user can call to process the transformation of a node but not
312 * serialize out automatically. ????????????????
313 *
314 * Does ElemTemplateElement.executeChildTemplates() cut it? It sends
315 * results out to the stream directly, so that could be a problem.
316 */
317 }