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: FuncPosition.java 468655 2006-10-28 07:12:06Z minchau $
020 */
021 package org.apache.xpath.functions;
022
023 import org.apache.xml.dtm.DTM;
024 import org.apache.xml.dtm.DTMIterator;
025 import org.apache.xpath.XPathContext;
026 import org.apache.xpath.axes.SubContextList;
027 import org.apache.xpath.compiler.Compiler;
028 import org.apache.xpath.objects.XNumber;
029 import org.apache.xpath.objects.XObject;
030
031 /**
032 * Execute the Position() function.
033 * @xsl.usage advanced
034 */
035 public class FuncPosition extends Function
036 {
037 static final long serialVersionUID = -9092846348197271582L;
038 private boolean m_isTopLevel;
039
040 /**
041 * Figure out if we're executing a toplevel expression.
042 * If so, we can't be inside of a predicate.
043 */
044 public void postCompileStep(Compiler compiler)
045 {
046 m_isTopLevel = compiler.getLocationPathDepth() == -1;
047 }
048
049 /**
050 * Get the position in the current context node list.
051 *
052 * @param xctxt Runtime XPath context.
053 *
054 * @return The current position of the itteration in the context node list,
055 * or -1 if there is no active context node list.
056 */
057 public int getPositionInContextNodeList(XPathContext xctxt)
058 {
059
060 // System.out.println("FuncPosition- entry");
061 // If we're in a predicate, then this will return non-null.
062 SubContextList iter = m_isTopLevel ? null : xctxt.getSubContextList();
063
064 if (null != iter)
065 {
066 int prox = iter.getProximityPosition(xctxt);
067
068 // System.out.println("FuncPosition- prox: "+prox);
069 return prox;
070 }
071
072 DTMIterator cnl = xctxt.getContextNodeList();
073
074 if (null != cnl)
075 {
076 int n = cnl.getCurrentNode();
077 if(n == DTM.NULL)
078 {
079 if(cnl.getCurrentPos() == 0)
080 return 0;
081
082 // Then I think we're in a sort. See sort21.xsl. So the iterator has
083 // already been spent, and is not on the node we're processing.
084 // It's highly possible that this is an issue for other context-list
085 // functions. Shouldn't be a problem for last(), and it shouldn't be
086 // a problem for current().
087 try
088 {
089 cnl = cnl.cloneWithReset();
090 }
091 catch(CloneNotSupportedException cnse)
092 {
093 throw new org.apache.xml.utils.WrappedRuntimeException(cnse);
094 }
095 int currentNode = xctxt.getContextNode();
096 // System.out.println("currentNode: "+currentNode);
097 while(DTM.NULL != (n = cnl.nextNode()))
098 {
099 if(n == currentNode)
100 break;
101 }
102 }
103 // System.out.println("n: "+n);
104 // System.out.println("FuncPosition- cnl.getCurrentPos(): "+cnl.getCurrentPos());
105 return cnl.getCurrentPos();
106 }
107
108 // System.out.println("FuncPosition - out of guesses: -1");
109 return -1;
110 }
111
112 /**
113 * Execute the function. The function must return
114 * a valid object.
115 * @param xctxt The current execution context.
116 * @return A valid XObject.
117 *
118 * @throws javax.xml.transform.TransformerException
119 */
120 public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
121 {
122 double pos = (double) getPositionInContextNodeList(xctxt);
123
124 return new XNumber(pos);
125 }
126
127 /**
128 * No arguments to process, so this does nothing.
129 */
130 public void fixupVariables(java.util.Vector vars, int globalsSize)
131 {
132 // no-op
133 }
134 }