Home | History | Annotate | Download | only in templates
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one
      3  * or more contributor license agreements. See the NOTICE file
      4  * distributed with this work for additional information
      5  * regarding copyright ownership. The ASF licenses this file
      6  * to you under the Apache License, Version 2.0 (the  "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  */
     18 /*
     19  * $Id: ElemApplyTemplates.java 468643 2006-10-28 06:56:03Z minchau $
     20  */
     21 package org.apache.xalan.templates;
     22 
     23 import java.util.Vector;
     24 
     25 import javax.xml.transform.TransformerException;
     26 
     27 import org.apache.xalan.transformer.TransformerImpl;
     28 import org.apache.xml.dtm.DTM;
     29 import org.apache.xml.dtm.DTMIterator;
     30 import org.apache.xml.serializer.SerializationHandler;
     31 import org.apache.xml.utils.IntStack;
     32 import org.apache.xml.utils.QName;
     33 import org.apache.xpath.VariableStack;
     34 import org.apache.xpath.XPath;
     35 import org.apache.xpath.XPathContext;
     36 import org.apache.xpath.objects.XObject;
     37 import org.xml.sax.SAXException;
     38 
     39 /**
     40  * Implement xsl:apply-templates.
     41  * <pre>
     42  * &amp;!ELEMENT xsl:apply-templates (xsl:sort|xsl:with-param)*>
     43  * &amp;!ATTLIST xsl:apply-templates
     44  *   select %expr; "node()"
     45  *   mode %qname; #IMPLIED
     46  * &amp;
     47  * </pre>
     48  * @see <a href="http://www.w3.org/TR/xslt#section-Applying-Template-Rules">section-Applying-Template-Rules in XSLT Specification</a>
     49  * @xsl.usage advanced
     50  */
     51 public class ElemApplyTemplates extends ElemCallTemplate
     52 {
     53     static final long serialVersionUID = 2903125371542621004L;
     54 
     55   /**
     56    * mode %qname; #IMPLIED
     57    * @serial
     58    */
     59   private QName m_mode = null;
     60 
     61   /**
     62    * Set the mode attribute for this element.
     63    *
     64    * @param mode reference, which may be null, to the <a href="http://www.w3.org/TR/xslt#modes">current mode</a>.
     65    */
     66   public void setMode(QName mode)
     67   {
     68     m_mode = mode;
     69   }
     70 
     71   /**
     72    * Get the mode attribute for this element.
     73    *
     74    * @return The mode attribute for this element
     75    */
     76   public QName getMode()
     77   {
     78     return m_mode;
     79   }
     80 
     81   /**
     82    * Tells if this belongs to a default template,
     83    * in which case it will act different with
     84    * regard to processing modes.
     85    * @see <a href="http://www.w3.org/TR/xslt#built-in-rule">built-in-rule in XSLT Specification</a>
     86    * @serial
     87    */
     88   private boolean m_isDefaultTemplate = false;
     89 
     90 //  /**
     91 //   * List of namespace/localname IDs, for identification of xsl:with-param to
     92 //   * xsl:params.  Initialized in the compose() method.
     93 //   */
     94 //  private int[] m_paramIDs;
     95 
     96   /**
     97    * Set if this belongs to a default template,
     98    * in which case it will act different with
     99    * regard to processing modes.
    100    * @see <a href="http://www.w3.org/TR/xslt#built-in-rule">built-in-rule in XSLT Specification</a>
    101    *
    102    * @param b boolean value to set.
    103    */
    104   public void setIsDefaultTemplate(boolean b)
    105   {
    106     m_isDefaultTemplate = b;
    107   }
    108 
    109   /**
    110    * Get an int constant identifying the type of element.
    111    * @see org.apache.xalan.templates.Constants
    112    *
    113    * @return Token ID for this element types
    114    */
    115   public int getXSLToken()
    116   {
    117     return Constants.ELEMNAME_APPLY_TEMPLATES;
    118   }
    119 
    120   /**
    121    * This function is called after everything else has been
    122    * recomposed, and allows the template to set remaining
    123    * values that may be based on some other property that
    124    * depends on recomposition.
    125    */
    126   public void compose(StylesheetRoot sroot) throws TransformerException
    127   {
    128     super.compose(sroot);
    129   }
    130 
    131   /**
    132    * Return the node name.
    133    *
    134    * @return Element name
    135    */
    136   public String getNodeName()
    137   {
    138     return Constants.ELEMNAME_APPLY_TEMPLATES_STRING;
    139   }
    140 
    141   /**
    142    * Apply the context node to the matching templates.
    143    * @see <a href="http://www.w3.org/TR/xslt#section-Applying-Template-Rules">section-Applying-Template-Rules in XSLT Specification</a>
    144    *
    145    * @param transformer non-null reference to the the current transform-time state.
    146    *
    147    * @throws TransformerException
    148    */
    149   public void execute(TransformerImpl transformer) throws TransformerException
    150   {
    151 
    152     transformer.pushCurrentTemplateRuleIsNull(false);
    153 
    154     boolean pushMode = false;
    155 
    156     try
    157     {
    158       // %REVIEW% Do we need this check??
    159       //      if (null != sourceNode)
    160       //      {
    161       // boolean needToTurnOffInfiniteLoopCheck = false;
    162       QName mode = transformer.getMode();
    163 
    164       if (!m_isDefaultTemplate)
    165       {
    166         if (((null == mode) && (null != m_mode))
    167                 || ((null != mode) &&!mode.equals(m_mode)))
    168         {
    169           pushMode = true;
    170 
    171           transformer.pushMode(m_mode);
    172         }
    173       }
    174 
    175       transformSelectedNodes(transformer);
    176     }
    177     finally
    178     {
    179       if (pushMode)
    180         transformer.popMode();
    181 
    182       transformer.popCurrentTemplateRuleIsNull();
    183     }
    184   }
    185 
    186 
    187   /**
    188    * Perform a query if needed, and call transformNode for each child.
    189    *
    190    * @param transformer non-null reference to the the current transform-time state.
    191    *
    192    * @throws TransformerException Thrown in a variety of circumstances.
    193    * @xsl.usage advanced
    194    */
    195   public void transformSelectedNodes(TransformerImpl transformer)
    196             throws TransformerException
    197   {
    198 
    199     final XPathContext xctxt = transformer.getXPathContext();
    200     final int sourceNode = xctxt.getCurrentNode();
    201     DTMIterator sourceNodes = m_selectExpression.asIterator(xctxt, sourceNode);
    202     VariableStack vars = xctxt.getVarStack();
    203     int nParams = getParamElemCount();
    204     int thisframe = vars.getStackFrame();
    205 
    206     boolean pushContextNodeListFlag = false;
    207 
    208     try
    209     {
    210 
    211             xctxt.pushCurrentNode(DTM.NULL);
    212             xctxt.pushCurrentExpressionNode(DTM.NULL);
    213             xctxt.pushSAXLocatorNull();
    214             transformer.pushElemTemplateElement(null);
    215       final Vector keys = (m_sortElems == null)
    216                           ? null
    217                           : transformer.processSortKeys(this, sourceNode);
    218 
    219       // Sort if we need to.
    220       if (null != keys)
    221         sourceNodes = sortNodes(xctxt, keys, sourceNodes);
    222 
    223       final SerializationHandler rth = transformer.getSerializationHandler();
    224 //      ContentHandler chandler = rth.getContentHandler();
    225       final StylesheetRoot sroot = transformer.getStylesheet();
    226       final TemplateList tl = sroot.getTemplateListComposed();
    227       final boolean quiet = transformer.getQuietConflictWarnings();
    228 
    229       // Should be able to get this from the iterator but there must be a bug.
    230       DTM dtm = xctxt.getDTM(sourceNode);
    231 
    232       int argsFrame = -1;
    233       if(nParams > 0)
    234       {
    235         // This code will create a section on the stack that is all the
    236         // evaluated arguments.  These will be copied into the real params
    237         // section of each called template.
    238         argsFrame = vars.link(nParams);
    239         vars.setStackFrame(thisframe);
    240 
    241         for (int i = 0; i < nParams; i++)
    242         {
    243           ElemWithParam ewp = m_paramElems[i];
    244           XObject obj = ewp.getValue(transformer, sourceNode);
    245 
    246           vars.setLocalVariable(i, obj, argsFrame);
    247         }
    248         vars.setStackFrame(argsFrame);
    249       }
    250 
    251       xctxt.pushContextNodeList(sourceNodes);
    252       pushContextNodeListFlag = true;
    253 
    254       IntStack currentNodes = xctxt.getCurrentNodeStack();
    255 
    256       IntStack currentExpressionNodes = xctxt.getCurrentExpressionNodeStack();
    257 
    258       // pushParams(transformer, xctxt);
    259 
    260       int child;
    261       while (DTM.NULL != (child = sourceNodes.nextNode()))
    262       {
    263         currentNodes.setTop(child);
    264         currentExpressionNodes.setTop(child);
    265 
    266         if(xctxt.getDTM(child) != dtm)
    267         {
    268           dtm = xctxt.getDTM(child);
    269         }
    270 
    271         final int exNodeType = dtm.getExpandedTypeID(child);
    272 
    273         final int nodeType = dtm.getNodeType(child);
    274 
    275         final QName mode = transformer.getMode();
    276 
    277         ElemTemplate template = tl.getTemplateFast(xctxt, child, exNodeType, mode,
    278                                       -1, quiet, dtm);
    279 
    280         // If that didn't locate a node, fall back to a default template rule.
    281         // See http://www.w3.org/TR/xslt#built-in-rule.
    282         if (null == template)
    283         {
    284           switch (nodeType)
    285           {
    286           case DTM.DOCUMENT_FRAGMENT_NODE :
    287           case DTM.ELEMENT_NODE :
    288             template = sroot.getDefaultRule();
    289             // %OPT% direct faster?
    290             break;
    291           case DTM.ATTRIBUTE_NODE :
    292           case DTM.CDATA_SECTION_NODE :
    293           case DTM.TEXT_NODE :
    294             // if(rth.m_elemIsPending || rth.m_docPending)
    295             //  rth.flushPending(true);
    296             transformer.pushPairCurrentMatched(sroot.getDefaultTextRule(), child);
    297             transformer.setCurrentElement(sroot.getDefaultTextRule());
    298             // dtm.dispatchCharactersEvents(child, chandler, false);
    299             dtm.dispatchCharactersEvents(child, rth, false);
    300             transformer.popCurrentMatched();
    301             continue;
    302           case DTM.DOCUMENT_NODE :
    303             template = sroot.getDefaultRootRule();
    304             break;
    305           default :
    306 
    307             // No default rules for processing instructions and the like.
    308             continue;
    309           }
    310         }
    311         else
    312         {
    313         	transformer.setCurrentElement(template);
    314         }
    315 
    316         transformer.pushPairCurrentMatched(template, child);
    317 
    318         int currentFrameBottom;  // See comment with unlink, below
    319         if(template.m_frameSize > 0)
    320         {
    321           xctxt.pushRTFContext();
    322           currentFrameBottom = vars.getStackFrame();  // See comment with unlink, below
    323           vars.link(template.m_frameSize);
    324           // You can't do the check for nParams here, otherwise the
    325           // xsl:params might not be nulled.
    326           if(/* nParams > 0 && */ template.m_inArgsSize > 0)
    327           {
    328             int paramIndex = 0;
    329             for (ElemTemplateElement elem = template.getFirstChildElem();
    330                  null != elem; elem = elem.getNextSiblingElem())
    331             {
    332               if(Constants.ELEMNAME_PARAMVARIABLE == elem.getXSLToken())
    333               {
    334                 ElemParam ep = (ElemParam)elem;
    335 
    336                 int i;
    337                 for (i = 0; i < nParams; i++)
    338                 {
    339                   ElemWithParam ewp = m_paramElems[i];
    340                   if(ewp.m_qnameID == ep.m_qnameID)
    341                   {
    342                     XObject obj = vars.getLocalVariable(i, argsFrame);
    343                     vars.setLocalVariable(paramIndex, obj);
    344                     break;
    345                   }
    346                 }
    347                 if(i == nParams)
    348                   vars.setLocalVariable(paramIndex, null);
    349               }
    350               else
    351                 break;
    352               paramIndex++;
    353             }
    354 
    355           }
    356         }
    357         else
    358         	currentFrameBottom = 0;
    359 
    360         // And execute the child templates.
    361         // Loop through the children of the template, calling execute on
    362         // each of them.
    363         for (ElemTemplateElement t = template.m_firstChild;
    364              t != null; t = t.m_nextSibling)
    365         {
    366           xctxt.setSAXLocator(t);
    367           try
    368           {
    369           	transformer.pushElemTemplateElement(t);
    370           	t.execute(transformer);
    371           }
    372           finally
    373           {
    374           	transformer.popElemTemplateElement();
    375           }
    376         }
    377 
    378         if(template.m_frameSize > 0)
    379         {
    380           // See Frank Weiss bug around 03/19/2002 (no Bugzilla report yet).
    381           // While unlink will restore to the proper place, the real position
    382           // may have been changed for xsl:with-param, so that variables
    383           // can be accessed.
    384           // of right now.
    385           // More:
    386           // When we entered this function, the current
    387           // frame buffer (cfb) index in the variable stack may
    388           // have been manually set.  If we just call
    389           // unlink(), however, it will restore the cfb to the
    390           // previous link index from the link stack, rather than
    391           // the manually set cfb.  So,
    392           // the only safe solution is to restore it back
    393           // to the same position it was on entry, since we're
    394           // really not working in a stack context here. (Bug4218)
    395           vars.unlink(currentFrameBottom);
    396           xctxt.popRTFContext();
    397         }
    398 
    399         transformer.popCurrentMatched();
    400 
    401       } // end while (DTM.NULL != (child = sourceNodes.nextNode()))
    402     }
    403     catch (SAXException se)
    404     {
    405       transformer.getErrorListener().fatalError(new TransformerException(se));
    406     }
    407     finally
    408     {
    409       // Unlink to the original stack frame
    410       if(nParams > 0)
    411         vars.unlink(thisframe);
    412       xctxt.popSAXLocator();
    413       if (pushContextNodeListFlag) xctxt.popContextNodeList();
    414       transformer.popElemTemplateElement();
    415       xctxt.popCurrentExpressionNode();
    416       xctxt.popCurrentNode();
    417       sourceNodes.detach();
    418     }
    419   }
    420 
    421 }
    422