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: FunctionPattern.java 468655 2006-10-28 07:12:06Z minchau $
020     */
021    package org.apache.xpath.patterns;
022    
023    import org.apache.xml.dtm.DTM;
024    import org.apache.xml.dtm.DTMIterator;
025    import org.apache.xpath.Expression;
026    import org.apache.xpath.ExpressionOwner;
027    import org.apache.xpath.XPathContext;
028    import org.apache.xpath.XPathVisitor;
029    import org.apache.xpath.objects.XNumber;
030    import org.apache.xpath.objects.XObject;
031    
032    /**
033     * Match pattern step that contains a function.
034     * @xsl.usage advanced
035     */
036    public class FunctionPattern extends StepPattern
037    {
038        static final long serialVersionUID = -5426793413091209944L;
039    
040      /**
041       * Construct a FunctionPattern from a
042       * {@link org.apache.xpath.functions.Function expression}.
043       *
044       * NEEDSDOC @param expr
045       */
046      public FunctionPattern(Expression expr, int axis, int predaxis)
047      {
048    
049        super(0, null, null, axis, predaxis);
050    
051        m_functionExpr = expr;
052      }
053    
054      /**
055       * Static calc of match score.
056       */
057      public final void calcScore()
058      {
059    
060        m_score = SCORE_OTHER;
061    
062        if (null == m_targetString)
063          calcTargetString();
064      }
065    
066      /**
067       * Should be a {@link org.apache.xpath.functions.Function expression}.
068       *  @serial   
069       */
070      Expression m_functionExpr;
071      
072      /**
073       * This function is used to fixup variables from QNames to stack frame 
074       * indexes at stylesheet build time.
075       * @param vars List of QNames that correspond to variables.  This list 
076       * should be searched backwards for the first qualified name that 
077       * corresponds to the variable reference qname.  The position of the 
078       * QName in the vector from the start of the vector will be its position 
079       * in the stack frame (but variables above the globalsTop value will need 
080       * to be offset to the current stack frame).
081       */
082      public void fixupVariables(java.util.Vector vars, int globalsSize)
083      {
084        super.fixupVariables(vars, globalsSize);
085        m_functionExpr.fixupVariables(vars, globalsSize);
086      }
087    
088      
089      /**
090       * Test a node to see if it matches the given node test.
091       *
092       * @param xctxt XPath runtime context.
093       *
094       * @return {@link org.apache.xpath.patterns.NodeTest#SCORE_NODETEST},
095       *         {@link org.apache.xpath.patterns.NodeTest#SCORE_NONE},
096       *         {@link org.apache.xpath.patterns.NodeTest#SCORE_NSWILD},
097       *         {@link org.apache.xpath.patterns.NodeTest#SCORE_QNAME}, or
098       *         {@link org.apache.xpath.patterns.NodeTest#SCORE_OTHER}.
099       *
100       * @throws javax.xml.transform.TransformerException
101       */
102      public XObject execute(XPathContext xctxt, int context)
103              throws javax.xml.transform.TransformerException
104      {
105    
106        DTMIterator nl = m_functionExpr.asIterator(xctxt, context);
107        XNumber score = SCORE_NONE;
108    
109        if (null != nl)
110        {
111          int n;
112    
113          while (DTM.NULL != (n = nl.nextNode()))
114          {
115            score = (n == context) ? SCORE_OTHER : SCORE_NONE;
116    
117            if (score == SCORE_OTHER)
118            {
119              context = n;
120    
121              break;
122            }
123          }
124    
125          // nl.detach();
126        }
127        nl.detach();
128    
129        return score;
130      }
131      
132      /**
133       * Test a node to see if it matches the given node test.
134       *
135       * @param xctxt XPath runtime context.
136       *
137       * @return {@link org.apache.xpath.patterns.NodeTest#SCORE_NODETEST},
138       *         {@link org.apache.xpath.patterns.NodeTest#SCORE_NONE},
139       *         {@link org.apache.xpath.patterns.NodeTest#SCORE_NSWILD},
140       *         {@link org.apache.xpath.patterns.NodeTest#SCORE_QNAME}, or
141       *         {@link org.apache.xpath.patterns.NodeTest#SCORE_OTHER}.
142       *
143       * @throws javax.xml.transform.TransformerException
144       */
145      public XObject execute(XPathContext xctxt, int context, 
146                             DTM dtm, int expType)
147              throws javax.xml.transform.TransformerException
148      {
149    
150        DTMIterator nl = m_functionExpr.asIterator(xctxt, context);
151        XNumber score = SCORE_NONE;
152    
153        if (null != nl)
154        {
155          int n;
156    
157          while (DTM.NULL != (n = nl.nextNode()))
158          {
159            score = (n == context) ? SCORE_OTHER : SCORE_NONE;
160    
161            if (score == SCORE_OTHER)
162            {
163              context = n;
164    
165              break;
166            }
167          }
168    
169          nl.detach();
170        }
171    
172        return score;
173      }
174      
175      /**
176       * Test a node to see if it matches the given node test.
177       *
178       * @param xctxt XPath runtime context.
179       *
180       * @return {@link org.apache.xpath.patterns.NodeTest#SCORE_NODETEST},
181       *         {@link org.apache.xpath.patterns.NodeTest#SCORE_NONE},
182       *         {@link org.apache.xpath.patterns.NodeTest#SCORE_NSWILD},
183       *         {@link org.apache.xpath.patterns.NodeTest#SCORE_QNAME}, or
184       *         {@link org.apache.xpath.patterns.NodeTest#SCORE_OTHER}.
185       *
186       * @throws javax.xml.transform.TransformerException
187       */
188      public XObject execute(XPathContext xctxt)
189              throws javax.xml.transform.TransformerException
190      {
191    
192        int context = xctxt.getCurrentNode();
193        DTMIterator nl = m_functionExpr.asIterator(xctxt, context);
194        XNumber score = SCORE_NONE;
195    
196        if (null != nl)
197        {
198          int n;
199    
200          while (DTM.NULL != (n = nl.nextNode()))
201          {
202            score = (n == context) ? SCORE_OTHER : SCORE_NONE;
203    
204            if (score == SCORE_OTHER)
205            {
206              context = n;
207    
208              break;
209            }
210          }
211    
212          nl.detach();
213        }
214    
215        return score;
216      }
217      
218      class FunctionOwner implements ExpressionOwner
219      {
220        /**
221         * @see ExpressionOwner#getExpression()
222         */
223        public Expression getExpression()
224        {
225          return m_functionExpr;
226        }
227    
228    
229        /**
230         * @see ExpressionOwner#setExpression(Expression)
231         */
232        public void setExpression(Expression exp)
233        {
234            exp.exprSetParent(FunctionPattern.this);
235            m_functionExpr = exp;
236        }
237      }
238      
239      /**
240       * Call the visitor for the function.
241       */
242      protected void callSubtreeVisitors(XPathVisitor visitor)
243      {
244        m_functionExpr.callVisitors(new FunctionOwner(), visitor);
245        super.callSubtreeVisitors(visitor);
246      }
247    
248    }