1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xpath.internal.functions;
  22 
  23 import com.sun.org.apache.xml.internal.dtm.DTM;
  24 import com.sun.org.apache.xml.internal.dtm.DTMIterator;
  25 import com.sun.org.apache.xml.internal.utils.QName;
  26 import com.sun.org.apache.xpath.internal.XPathContext;
  27 import com.sun.org.apache.xpath.internal.axes.SubContextList;
  28 import com.sun.org.apache.xpath.internal.compiler.Compiler;
  29 import com.sun.org.apache.xpath.internal.objects.XNumber;
  30 import com.sun.org.apache.xpath.internal.objects.XObject;
  31 import java.util.List;
  32 
  33 /**
  34  * Execute the Position() function.
  35  * @xsl.usage advanced
  36  * @LastModified: Oct 2017
  37  */
  38 public class FuncPosition extends Function
  39 {
  40     static final long serialVersionUID = -9092846348197271582L;
  41   private boolean m_isTopLevel;
  42 
  43   /**
  44    * Figure out if we're executing a toplevel expression.
  45    * If so, we can't be inside of a predicate.
  46    */
  47   public void postCompileStep(Compiler compiler)
  48   {
  49     m_isTopLevel = compiler.getLocationPathDepth() == -1;
  50   }
  51 
  52   /**
  53    * Get the position in the current context node list.
  54    *
  55    * @param xctxt Runtime XPath context.
  56    *
  57    * @return The current position of the itteration in the context node list,
  58    *         or -1 if there is no active context node list.
  59    */
  60   public int getPositionInContextNodeList(XPathContext xctxt)
  61   {
  62 
  63     // System.out.println("FuncPosition- entry");
  64     // If we're in a predicate, then this will return non-null.
  65     SubContextList iter = m_isTopLevel ? null : xctxt.getSubContextList();
  66 
  67     if (null != iter)
  68     {
  69       int prox = iter.getProximityPosition(xctxt);
  70 
  71       // System.out.println("FuncPosition- prox: "+prox);
  72       return prox;
  73     }
  74 
  75     DTMIterator cnl = xctxt.getContextNodeList();
  76 
  77     if (null != cnl)
  78     {
  79       int n = cnl.getCurrentNode();
  80       if(n == DTM.NULL)
  81       {
  82         if(cnl.getCurrentPos() == 0)
  83           return 0;
  84 
  85         // Then I think we're in a sort.  See sort21.xsl. So the iterator has
  86         // already been spent, and is not on the node we're processing.
  87         // It's highly possible that this is an issue for other context-list
  88         // functions.  Shouldn't be a problem for last(), and it shouldn't be
  89         // a problem for current().
  90         try
  91         {
  92           cnl = cnl.cloneWithReset();
  93         }
  94         catch(CloneNotSupportedException cnse)
  95         {
  96           throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(cnse);
  97         }
  98         int currentNode = xctxt.getContextNode();
  99         // System.out.println("currentNode: "+currentNode);
 100         while(DTM.NULL != (n = cnl.nextNode()))
 101         {
 102           if(n == currentNode)
 103             break;
 104         }
 105       }
 106       // System.out.println("n: "+n);
 107       // System.out.println("FuncPosition- cnl.getCurrentPos(): "+cnl.getCurrentPos());
 108       return cnl.getCurrentPos();
 109     }
 110 
 111     // System.out.println("FuncPosition - out of guesses: -1");
 112     return -1;
 113   }
 114 
 115   /**
 116    * Execute the function.  The function must return
 117    * a valid object.
 118    * @param xctxt The current execution context.
 119    * @return A valid XObject.
 120    *
 121    * @throws javax.xml.transform.TransformerException
 122    */
 123   public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
 124   {
 125     double pos = (double) getPositionInContextNodeList(xctxt);
 126 
 127     return new XNumber(pos);
 128   }
 129 
 130   /**
 131    * No arguments to process, so this does nothing.
 132    */
 133   public void fixupVariables(List<QName> vars, int globalsSize)
 134   {
 135     // no-op
 136   }
 137 }