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: FunctionPattern.java 468655 2006-10-28 07:12:06Z minchau $
20 */
21package org.apache.xpath.patterns;
22
23import org.apache.xml.dtm.DTM;
24import org.apache.xml.dtm.DTMIterator;
25import org.apache.xpath.Expression;
26import org.apache.xpath.ExpressionOwner;
27import org.apache.xpath.XPathContext;
28import org.apache.xpath.XPathVisitor;
29import org.apache.xpath.objects.XNumber;
30import org.apache.xpath.objects.XObject;
31
32/**
33 * Match pattern step that contains a function.
34 * @xsl.usage advanced
35 */
36public class FunctionPattern extends StepPattern
37{
38    static final long serialVersionUID = -5426793413091209944L;
39
40  /**
41   * Construct a FunctionPattern from a
42   * {@link org.apache.xpath.functions.Function expression}.
43   *
44   * NEEDSDOC @param expr
45   */
46  public FunctionPattern(Expression expr, int axis, int predaxis)
47  {
48
49    super(0, null, null, axis, predaxis);
50
51    m_functionExpr = expr;
52  }
53
54  /**
55   * Static calc of match score.
56   */
57  public final void calcScore()
58  {
59
60    m_score = SCORE_OTHER;
61
62    if (null == m_targetString)
63      calcTargetString();
64  }
65
66  /**
67   * Should be a {@link org.apache.xpath.functions.Function expression}.
68   *  @serial
69   */
70  Expression m_functionExpr;
71
72  /**
73   * This function is used to fixup variables from QNames to stack frame
74   * indexes at stylesheet build time.
75   * @param vars List of QNames that correspond to variables.  This list
76   * should be searched backwards for the first qualified name that
77   * corresponds to the variable reference qname.  The position of the
78   * QName in the vector from the start of the vector will be its position
79   * in the stack frame (but variables above the globalsTop value will need
80   * to be offset to the current stack frame).
81   */
82  public void fixupVariables(java.util.Vector vars, int globalsSize)
83  {
84    super.fixupVariables(vars, globalsSize);
85    m_functionExpr.fixupVariables(vars, globalsSize);
86  }
87
88
89  /**
90   * Test a node to see if it matches the given node test.
91   *
92   * @param xctxt XPath runtime context.
93   *
94   * @return {@link org.apache.xpath.patterns.NodeTest#SCORE_NODETEST},
95   *         {@link org.apache.xpath.patterns.NodeTest#SCORE_NONE},
96   *         {@link org.apache.xpath.patterns.NodeTest#SCORE_NSWILD},
97   *         {@link org.apache.xpath.patterns.NodeTest#SCORE_QNAME}, or
98   *         {@link org.apache.xpath.patterns.NodeTest#SCORE_OTHER}.
99   *
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}
249