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 }