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: ElemWithParam.java 468643 2006-10-28 06:56:03Z minchau $
020     */
021    package org.apache.xalan.templates;
022    
023    import javax.xml.transform.TransformerException;
024    
025    import org.apache.xalan.res.XSLTErrorResources;
026    import org.apache.xalan.transformer.TransformerImpl;
027    import org.apache.xml.utils.QName;
028    import org.apache.xpath.XPath;
029    import org.apache.xpath.XPathContext;
030    import org.apache.xpath.objects.XObject;
031    import org.apache.xpath.objects.XRTreeFrag;
032    import org.apache.xpath.objects.XString;
033    
034    /**
035     * Implement xsl:with-param.  xsl:with-param is allowed within
036     * both xsl:call-template and xsl:apply-templates.
037     * <pre>
038     * <!ELEMENT xsl:with-param %template;>
039     * <!ATTLIST xsl:with-param
040     *   name %qname; #REQUIRED
041     *   select %expr; #IMPLIED
042     * >
043     * </pre>
044     * @see <a href="http://www.w3.org/TR/xslt#element-with-param">element-with-param in XSLT Specification</a>
045     * @xsl.usage advanced
046     */
047    public class ElemWithParam extends ElemTemplateElement
048    {
049        static final long serialVersionUID = -1070355175864326257L;
050      /**
051       * This is the index to the stack frame being called, <emph>not</emph> the 
052       * stack frame that contains this element.
053       */
054      int m_index;
055    
056      /**
057       * The "select" attribute, which specifies the value of the
058       * argument, if element content is not specified.
059       * @serial
060       */
061      private XPath m_selectPattern = null;
062    
063      /**
064       * Set the "select" attribute.
065       * The "select" attribute specifies the value of the
066       * argument, if element content is not specified.
067       *
068       * @param v Value to set for the "select" attribute. 
069       */
070      public void setSelect(XPath v)
071      {
072        m_selectPattern = v;
073      }
074    
075      /**
076       * Get the "select" attribute.
077       * The "select" attribute specifies the value of the
078       * argument, if element content is not specified.
079       *
080       * @return Value of the "select" attribute. 
081       */
082      public XPath getSelect()
083      {
084        return m_selectPattern;
085      }
086    
087      /**
088       * The required name attribute specifies the name of the
089       * parameter (the variable the value of whose binding is
090       * to be replaced). The value of the name attribute is a QName,
091       * which is expanded as described in [2.4 Qualified Names].
092       * @serial
093       */
094      private QName m_qname = null;
095      
096      int m_qnameID;
097    
098      /**
099       * Set the "name" attribute.
100       * DJD
101       *
102       * @param v Value to set for the "name" attribute.
103       */
104      public void setName(QName v)
105      {
106        m_qname = v;
107      }
108    
109      /**
110       * Get the "name" attribute.
111       * DJD
112       *
113       * @return Value of the "name" attribute.
114       */
115      public QName getName()
116      {
117        return m_qname;
118      }
119    
120      /**
121       * Get an integer representation of the element type.
122       *
123       * @return An integer representation of the element, defined in the
124       *     Constants class.
125       * @see org.apache.xalan.templates.Constants
126       */
127      public int getXSLToken()
128      {
129        return Constants.ELEMNAME_WITHPARAM;
130      }
131    
132    
133      /**
134       * Return the node name.
135       *
136       * @return the node name.
137       */
138      public String getNodeName()
139      {
140        return Constants.ELEMNAME_WITHPARAM_STRING;
141      }
142      
143      /**
144       * This function is called after everything else has been
145       * recomposed, and allows the template to set remaining
146       * values that may be based on some other property that
147       * depends on recomposition.
148       */
149      public void compose(StylesheetRoot sroot) throws TransformerException
150      {
151        // See if we can reduce an RTF to a select with a string expression.
152        if(null == m_selectPattern  
153           && sroot.getOptimizer())
154        {
155          XPath newSelect = ElemVariable.rewriteChildToExpression(this);
156          if(null != newSelect)
157            m_selectPattern = newSelect;
158        }
159        m_qnameID = sroot.getComposeState().getQNameID(m_qname);
160        super.compose(sroot);
161        
162        java.util.Vector vnames = sroot.getComposeState().getVariableNames();
163        if(null != m_selectPattern)
164          m_selectPattern.fixupVariables(vnames, sroot.getComposeState().getGlobalsSize());
165          
166        // m_index must be resolved by ElemApplyTemplates and ElemCallTemplate!
167      }
168      
169      /**
170       * Set the parent as an ElemTemplateElement.
171       *
172       * @param p This node's parent as an ElemTemplateElement
173       */
174      public void setParentElem(ElemTemplateElement p)
175      {
176        super.setParentElem(p);
177        p.m_hasVariableDecl = true;
178      }
179      
180      /**
181       * Get the XObject representation of the variable.
182       *
183       * @param transformer non-null reference to the the current transform-time state.
184       * @param sourceNode non-null reference to the <a href="http://www.w3.org/TR/xslt#dt-current-node">current source node</a>.
185       *
186       * @return the XObject representation of the variable.
187       *
188       * @throws TransformerException
189       */
190      public XObject getValue(TransformerImpl transformer, int sourceNode)
191              throws TransformerException
192      {
193    
194        XObject var;
195        XPathContext xctxt = transformer.getXPathContext();
196    
197        xctxt.pushCurrentNode(sourceNode);
198    
199        try
200        {
201          if (null != m_selectPattern)
202          {
203            var = m_selectPattern.execute(xctxt, sourceNode, this);
204    
205            var.allowDetachToRelease(false);
206    
207            if (transformer.getDebug())
208              transformer.getTraceManager().fireSelectedEvent(sourceNode, this,
209                      "select", m_selectPattern, var);
210          }
211          else if (null == getFirstChildElem())
212          {
213            var = XString.EMPTYSTRING;
214          }
215          else
216          {
217    
218            // Use result tree fragment
219            int df = transformer.transformToRTF(this);
220    
221            var = new XRTreeFrag(df, xctxt, this);
222          }
223        }
224        finally
225        {
226          xctxt.popCurrentNode();
227        }
228    
229        return var;
230      }
231      
232      /**
233       * Call the children visitors.
234       * @param visitor The visitor whose appropriate method will be called.
235       */
236      protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
237      {
238            if(callAttrs && (null != m_selectPattern))
239                    m_selectPattern.getExpression().callVisitors(m_selectPattern, visitor);
240        super.callChildVisitors(visitor, callAttrs);
241      }
242      
243      /**
244       * Add a child to the child list. If the select attribute
245       * is present, an error will be raised.
246       *
247       * @param elem New element to append to this element's children list
248       *
249       * @return null if the select attribute was present, otherwise the 
250       * child just added to the child list 
251       */
252      public ElemTemplateElement appendChild(ElemTemplateElement elem)
253      {
254        // cannot have content and select
255        if (m_selectPattern != null)
256        {
257          error(XSLTErrorResources.ER_CANT_HAVE_CONTENT_AND_SELECT, 
258              new Object[]{"xsl:" + this.getNodeName()});
259          return null;
260        }
261        return super.appendChild(elem);
262      }
263    
264    
265    }