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    }