You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by mu...@apache.org on 2023/06/16 06:20:37 UTC

[xalan-java] branch xalan-j_xslt3.0 updated: improving xsl:iterate instruction's evaluation, as per XSLT 3.0 spec for xsl:iterate. adding few new related working test cases as well.

This is an automated email from the ASF dual-hosted git repository.

mukulg pushed a commit to branch xalan-j_xslt3.0
in repository https://gitbox.apache.org/repos/asf/xalan-java.git


The following commit(s) were added to refs/heads/xalan-j_xslt3.0 by this push:
     new e964417a improving xsl:iterate instruction's evaluation, as per XSLT 3.0 spec for xsl:iterate. adding few new related working test cases as well.
e964417a is described below

commit e964417a97e490cd0daf70ecee5fd0938654749a
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Fri Jun 16 11:50:19 2023 +0530

    improving xsl:iterate instruction's evaluation, as per XSLT 3.0 spec for xsl:iterate. adding few new related working test cases as well.
---
 src/org/apache/xalan/templates/ElemIterate.java    | 179 ++++-----------------
 .../apache/xalan/templates/ElemIterateBreak.java   |  55 +++++--
 .../xalan/templates/ElemIterateNextIteration.java  | 117 +++++++++++++-
 .../xalan/templates/ElemTemplateElement.java       |  56 +++++++
 .../templates/XslIterateParamWithparamData.java    |  69 ++++++++
 tests/org/apache/xalan/xslt3/XslIterateTests.java  |  20 +++
 tests/xsl_iterate/gold/test11.out                  |   6 +
 tests/xsl_iterate/gold/test12.out                  |   5 +
 tests/xsl_iterate/iterate-003.xsl                  |   2 +-
 tests/xsl_iterate/{iterate-003.xsl => test11.xsl}  |  49 +++---
 tests/xsl_iterate/test12.xsl                       |  62 +++++++
 tests/xsl_iterate/test1_c.xml                      |   7 +
 tests/xsl_iterate/test1_d.xml                      |   8 +
 13 files changed, 444 insertions(+), 191 deletions(-)

diff --git a/src/org/apache/xalan/templates/ElemIterate.java b/src/org/apache/xalan/templates/ElemIterate.java
index 9ee7c2b1..c3bb4885 100644
--- a/src/org/apache/xalan/templates/ElemIterate.java
+++ b/src/org/apache/xalan/templates/ElemIterate.java
@@ -26,17 +26,12 @@ import org.apache.xalan.transformer.TransformerImpl;
 import org.apache.xalan.xslt.util.XslTransformErrorLocatorHelper;
 import org.apache.xml.dtm.DTM;
 import org.apache.xml.dtm.DTMIterator;
-import org.apache.xml.dtm.DTMManager;
 import org.apache.xml.utils.IntStack;
 import org.apache.xml.utils.QName;
 import org.apache.xpath.Expression;
 import org.apache.xpath.ExpressionOwner;
-import org.apache.xpath.VariableStack;
 import org.apache.xpath.XPath;
 import org.apache.xpath.XPathContext;
-import org.apache.xpath.objects.XObject;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
 
 /**
  * XSLT 3.0 xsl:iterate element.
@@ -92,10 +87,11 @@ public class ElemIterate extends ElemTemplateElement implements ExpressionOwner
      private static final long serialVersionUID = -2692900882677332482L;
      
      private static final String OTHER_ELEM = "OTHER_ELEM";
-              
-     private List<ParamWithparamData> fParamList = new ArrayList<ParamWithparamData>();
      
-     private List<ParamWithparamData> fWithparamList = new ArrayList<ParamWithparamData>();
+     // revisit.
+     // can we have better way to maintain xsl:iterate->xsl:param* state, instead of having this with
+     // 'public static' visibility.
+     public static List<XslIterateParamWithparamData> fParamList = new ArrayList<XslIterateParamWithparamData>();
 
      /**
       * Construct an element representing xsl:iterate.
@@ -218,6 +214,10 @@ public class ElemIterate extends ElemTemplateElement implements ExpressionOwner
          
            final int sourceNode = xctxt.getCurrentNode();
            
+           // clear the, xsl:iterate->xsl:param* list storage before this xsl:iterate 
+           // instruction's evaluation.
+           fParamList.clear();
+           
            validateXslElemIterateChildElementsSequence(xctxt);
         
            DTMIterator sourceNodes = m_selectExpression.asIterator(xctxt, sourceNode);
@@ -234,8 +234,7 @@ public class ElemIterate extends ElemTemplateElement implements ExpressionOwner
                xctxt.pushSAXLocatorNull();
                xctxt.pushContextNodeList(sourceNodes);
                transformer.pushElemTemplateElement(null);                              
-           
-               int docID = sourceNode & DTMManager.IDENT_DTM_DEFAULT;
+                          
                int child;
                
                ElemIterateOnCompletion xslOnCompletionTemplate = null;
@@ -243,40 +242,23 @@ public class ElemIterate extends ElemTemplateElement implements ExpressionOwner
                while ((child = sourceNodes.nextNode()) != DTM.NULL) {
                    currentNodes.setTop(child);
                    currentExpressionNodes.setTop(child);
-
-                   if ((child & DTMManager.IDENT_DTM_DEFAULT) != docID)
-                   {
-                       docID = child & DTMManager.IDENT_DTM_DEFAULT;
-                   }                                  
-                   
+                                                                        
                    for (ElemTemplateElement elemTemplate = this.m_firstChild; elemTemplate != null; 
                                                                           elemTemplate = elemTemplate.m_nextSibling) {
                        if ((elemTemplate instanceof ElemIterateOnCompletion) && 
                                                                         (xslOnCompletionTemplate == null)) {
                            xslOnCompletionTemplate = (ElemIterateOnCompletion)elemTemplate;     
                        }
-                       else if (elemTemplate instanceof ElemIterateNextIteration) {
-                           VariableStack varStack = xctxt.getVarStack();
-                           for (int idx = 0; idx < fWithparamList.size(); idx++) {
-                               ParamWithparamData withParamData = fWithparamList.get(idx);
-                               XPath withParamSelectVal = withParamData.getSelectVal();                               
-                               XObject evalResult = withParamSelectVal.execute(xctxt, child, this);
-                               // update value of current xsl:next-iteration's current xsl:param 
-                               // 'parameter'. when xsl:iterate's new iteration is entered, this
-                               // parameter shall have this new value.
-                               varStack.setLocalVariable(idx, evalResult);
-                           }                           
-                       }
                        
-                       if (!((XslTransformErrorLocatorHelper.isXslIterateBreakEvaluated).booleanValue())) {
+                       if (!(XslTransformErrorLocatorHelper.isXslIterateBreakEvaluated).booleanValue()) {
                            xctxt.setSAXLocator(elemTemplate);
                            transformer.setCurrentElement(elemTemplate);
                            elemTemplate.execute(transformer);
                        }
                        else {
                            break;    
-                       }
-                   }
+                       }                                              
+                   }                                      
                    
                    if ((XslTransformErrorLocatorHelper.isXslIterateBreakEvaluated).booleanValue()) {                       
                        break;   
@@ -285,14 +267,14 @@ public class ElemIterate extends ElemTemplateElement implements ExpressionOwner
                
                if ((xslOnCompletionTemplate != null) && !(XslTransformErrorLocatorHelper.
                                                                                 isXslIterateBreakEvaluated).booleanValue()) {
-                  XslTransformErrorLocatorHelper.isXslIterateOnCompletionActive = Boolean.TRUE;
-                  xctxt.setSAXLocator(xslOnCompletionTemplate);
-                  transformer.setCurrentElement(xslOnCompletionTemplate);
-                  xslOnCompletionTemplate.execute(transformer);
-                  XslTransformErrorLocatorHelper.isXslIterateOnCompletionActive = Boolean.FALSE;
+                    XslTransformErrorLocatorHelper.isXslIterateOnCompletionActive = Boolean.TRUE;
+                    xctxt.setSAXLocator(xslOnCompletionTemplate);
+                    transformer.setCurrentElement(xslOnCompletionTemplate);
+                    xslOnCompletionTemplate.execute(transformer);
+                    XslTransformErrorLocatorHelper.isXslIterateOnCompletionActive = Boolean.FALSE;
                }
                
-               XslTransformErrorLocatorHelper.isXslIterateBreakEvaluated = Boolean.FALSE;
+               XslTransformErrorLocatorHelper.isXslIterateBreakEvaluated = Boolean.FALSE; 
            }
            finally {
               xctxt.popSAXLocator();
@@ -310,9 +292,8 @@ public class ElemIterate extends ElemTemplateElement implements ExpressionOwner
       
        /*
         * The XSLT 3.0 spec specifies constraints, about what should be the order of XSLT elements 
-        * xsl:param, xsl:on-completion and xsl:next-iteration within the xsl:iterate element. This 
-        * method ensures that, these XSLT xsl:iterate element constraints are validated during 
-        * an XSLT document transformation.  
+        * xsl:param and xsl:on-completion within the xsl:iterate element. This method ensures that, 
+        * these XSLT element constraints are validated during an XSLT stylesheet transformation.  
         */
       private void validateXslElemIterateChildElementsSequence(XPathContext xctxt) 
                                                                        throws TransformerException {
@@ -327,31 +308,23 @@ public class ElemIterate extends ElemTemplateElement implements ExpressionOwner
               }
               else if (elemTemplate instanceof ElemIterateOnCompletion) {
                   xslElemNamesList.add(Constants.ELEMNAME_ITERATE_ONCOMPLETION_STRING);   
-              }
-              else if (elemTemplate instanceof ElemIterateNextIteration) {
-                  xslElemNamesList.add(Constants.ELEMNAME_ITERATE_NEXTITERATION_STRING);   
-              }
+              }              
               else {
                   xslElemNamesList.add(OTHER_ELEM);
               }
           }
           
           // get index of specific item's first occurrence with the list object 'xslElemNamesList'.
-          // if a particular kind of xdm item that is checked is not present within the list object 
-          // 'xslElemNamesList', its index is returned as -1.
+          // if a particular kind of XSLT stylesheet item that is checked is not present within the 
+          // list object 'xslElemNamesList', its index is returned as -1.
           int paramIdx = xslElemNamesList.indexOf(Constants.ELEMNAME_PARAMVARIABLE_STRING);
-          int onCompletionIdx = xslElemNamesList.indexOf(Constants.ELEMNAME_ITERATE_ONCOMPLETION_STRING);
-          int nextIterationIdx = xslElemNamesList.indexOf(Constants.ELEMNAME_ITERATE_NEXTITERATION_STRING);
+          int onCompletionIdx = xslElemNamesList.indexOf(Constants.ELEMNAME_ITERATE_ONCOMPLETION_STRING);          
           int otherElemIdx = xslElemNamesList.indexOf(OTHER_ELEM);
           
           if ((paramIdx != -1) && (onCompletionIdx != -1) && (paramIdx > onCompletionIdx)) {
               throw new TransformerException("XTSE0010 : an xsl:param element must occur before xsl:on-completion "
                                                                                             + "element.", xctxt.getSAXLocator());    
-          }          
-          else if ((paramIdx != -1) && (nextIterationIdx != -1) && (paramIdx > nextIterationIdx)) {
-              throw new TransformerException("XTSE0010 : an xsl:param element must occur before xsl:next-iteration "
-                                                                                            + "element.", xctxt.getSAXLocator());
-          }
+          }                    
           else if ((paramIdx != -1) && (otherElemIdx != -1) && (paramIdx > otherElemIdx)) {
               throw new TransformerException("XTSE0010 : an xsl:param element must occur before any other element within "
                                                                                      + "xsl:iterate element.", xctxt.getSAXLocator());
@@ -360,22 +333,8 @@ public class ElemIterate extends ElemTemplateElement implements ExpressionOwner
                                                                                                  (otherElemIdx < onCompletionIdx)) {
               throw new TransformerException("XTSE0010 : an xsl:on-completion element must be the first child element of xsl:iterate "
                                                                                  + "after the xsl:param elements.", xctxt.getSAXLocator());
-          }
-          else if ((onCompletionIdx != -1) && (nextIterationIdx != -1) && (onCompletionIdx > nextIterationIdx)) {
-              throw new TransformerException("XTSE0010 : an xsl:on-completion element must occur before xsl:next-iteration "
-                                                                                                   + "element.", xctxt.getSAXLocator());
-          }
-          else if ((nextIterationIdx != -1) && (nextIterationIdx != (xslElemNamesList.size() - 1))) {
-              throw new TransformerException("XTSE3120 : an xsl:next-iteration element when present, must be the last instruction within "
-                                                                                         + "an xsl:iterate loop.", xctxt.getSAXLocator());
-          }
-          
-          // Validate the, xsl:iterate->xsl:param* and xsl:next-iteration->xsl:with-param* names, as per following XSLT 3.0 
-          // spec requirements,
-          // 1) All the xsl:param names must be unique.
-          // 2) All the xsl:next-iteration->xsl:with-param names must be unique.  
-          // 3) Value of name attribute of xsl:param's must be pair-wise equal to value of name attribute of 
-          //    xsl:next-iteration->xsl:with-param.          
+          }          
+                             
           if (paramIdx != -1) {
               for (ElemTemplateElement elemTemplate = this.m_firstChild; elemTemplate != null; 
                                                                                  elemTemplate = elemTemplate.m_nextSibling) {
@@ -383,7 +342,7 @@ public class ElemIterate extends ElemTemplateElement implements ExpressionOwner
                      ElemParam paramElem = (ElemParam)elemTemplate;
                      QName paramNameVal = paramElem.getName();
                      XPath paramSelectXPath = paramElem.getSelect();
-                     ParamWithparamData paramWithparamDataObj = new ParamWithparamData();
+                     XslIterateParamWithparamData paramWithparamDataObj = new XslIterateParamWithparamData();
                      paramWithparamDataObj.setNameVal(paramNameVal);
                      paramWithparamDataObj.setSelectVal(paramSelectXPath);
                      if (fParamList.contains(paramWithparamDataObj)) {
@@ -393,86 +352,8 @@ public class ElemIterate extends ElemTemplateElement implements ExpressionOwner
                      else {
                          fParamList.add(paramWithparamDataObj);    
                      }
-                  } 
-                  else if (elemTemplate instanceof ElemIterateNextIteration) {
-                      ElemIterateNextIteration elemIterateNextIteration = (ElemIterateNextIteration)elemTemplate;
-                      NodeList nextIterationChildNodes = elemIterateNextIteration.getChildNodes();
-                      for (int idx = 0; idx < nextIterationChildNodes.getLength(); idx++) {
-                          Node nextIterChild = nextIterationChildNodes.item(idx);
-                          if (nextIterChild instanceof ElemWithParam) {
-                              ElemWithParam withParamElem = (ElemWithParam)nextIterChild;
-                              QName withParamNameVal = withParamElem.getName();
-                              XPath withParamSelectXPath = withParamElem.getSelect();                              
-                              ParamWithparamData paramWithparamDataObj = new ParamWithparamData();
-                              paramWithparamDataObj.setNameVal(withParamNameVal);
-                              paramWithparamDataObj.setSelectVal(withParamSelectXPath);
-                              if (fWithparamList.contains(paramWithparamDataObj)) {
-                                 throw new TransformerException("XTSE0670 : duplicate xsl:with-param parameter name '" + withParamNameVal + 
-                                                                                                                      "'", xctxt.getSAXLocator());   
-                              }
-                              else {
-                                 fWithparamList.add(paramWithparamDataObj);  
-                              }
-                          }
-                      }
-                  }                  
-              }
-              
-              if (fParamList.size() != fWithparamList.size()) {
-                  throw new TransformerException("XTSE0580 : within xsl:iterate, the number of xsl:param elements are not equal to "
-                                                                 + "number of xsl:next-iteration's xsl:with-param elements.", xctxt.getSAXLocator());     
-              }
-              else {
-                 for (int idx = 0; idx < fParamList.size(); idx ++) {
-                     ParamWithparamData paramData = fParamList.get(idx);
-                     ParamWithparamData withParamData = fWithparamList.get(idx);
-                     if (!(paramData.getNameVal()).equals(withParamData.getNameVal())) {
-                         throw new TransformerException("XTSE3130 : within xsl:iterate, xsl:param and xsl:with-param names at position " + 
-                                                                                                (idx + 1) + " are not same.", xctxt.getSAXLocator());        
-                     }
-                 }
-              }
-          }
-          
-      }
-      
-      /*
-       * An object of this class, stores information about, one xsl:param 
-       * element or one xsl:next-iteration->xsl:with-param element, for a 
-       * particular xsl:iterate instruction. 
-       */
-      class ParamWithparamData {
-          
-          public QName nameVal;
-          
-          public XPath selectVal;
-
-          public QName getNameVal() {
-              return nameVal;
-          }
-
-          public void setNameVal(QName nameVal) {
-              this.nameVal = nameVal;
-          }
-
-          public XPath getSelectVal() {
-              return selectVal;
-          }
-
-          public void setSelectVal(XPath selectVal) {
-              this.selectVal = selectVal;
-          }
-          
-          @Override
-          public boolean equals(Object obj) {
-              if (this == obj) {
-                  return true;
-              }
-              if (obj == null || getClass() != obj.getClass()) {
-                  return false;
+                  }                                    
               }
-              ParamWithparamData paramWithparamData = (ParamWithparamData)obj;
-              return nameVal.equals(paramWithparamData.getNameVal());
           }
           
       }
diff --git a/src/org/apache/xalan/templates/ElemIterateBreak.java b/src/org/apache/xalan/templates/ElemIterateBreak.java
index 2135d561..6bb57128 100644
--- a/src/org/apache/xalan/templates/ElemIterateBreak.java
+++ b/src/org/apache/xalan/templates/ElemIterateBreak.java
@@ -154,16 +154,28 @@ public class ElemIterateBreak extends ElemTemplateElement implements ExpressionO
        */
        public void execute(TransformerImpl transformer) throws TransformerException
        {
-           if (this.m_nextSibling != null) {
-              XPathContext xpathContext = transformer.getXPathContext();
-              throw new TransformerException("XTSE3120 : an xsl:break instruction must not have any other "
-                                                                        + "stylesheet element as its following sibling.", 
-                                                                                         xpathContext.getSAXLocator());    
-           }
-           else {              
-              transformXslBreakInstruction(transformer);
-              XslTransformErrorLocatorHelper.isXslIterateBreakEvaluated = Boolean.TRUE;
-           }
+            XPathContext xpathContext = transformer.getXPathContext();
+            
+            boolean isXslBreakDescendantOfXslIterate = false;
+            
+            if (isXslBreakDescendantOfXslIterate(this)) {
+                isXslBreakDescendantOfXslIterate = true;    
+            }
+            else {
+                throw new TransformerException("XTSE3120 : an xsl:break instruction doesn't have "
+                                                                 + "xsl:iterate instruction as ancestor.", 
+                                                                                   xpathContext.getSAXLocator());   
+            }
+                      
+            if (isXslBreakDescendantOfXslIterate && isXslInstructionInTailPositionOfSequenceConstructor(this)) {              
+                transformXslBreakInstruction(transformer);
+                XslTransformErrorLocatorHelper.isXslIterateBreakEvaluated = Boolean.TRUE;
+            }
+            else {
+                throw new TransformerException("XTSE3120 : an xsl:break instruction is not in a "
+                                                                + "tail position within the sequence constructor of currently "
+                                                                + "active xsl:iterate instruction.", xpathContext.getSAXLocator());    
+            }
        }
 
        /**
@@ -203,5 +215,28 @@ public class ElemIterateBreak extends ElemTemplateElement implements ExpressionO
               }
            }
        }
+       
+       /*
+        * Determine whether, an xsl:break instruction has xsl:iterate instruction 
+        * as ancestor. 
+        */
+       private boolean isXslBreakDescendantOfXslIterate(ElemIterateBreak xslNextInstr) {
+           
+           boolean isXslBreakDescendantOfXslIterate = false;
+           
+           ElemTemplateElement xslParentElement = xslNextInstr.m_parentNode;
+           
+           while (!isXslBreakDescendantOfXslIterate && (xslParentElement != null)) {
+              if (xslParentElement instanceof ElemIterate) {
+                  isXslBreakDescendantOfXslIterate = true;
+                  break;
+              }
+              else {
+                  xslParentElement = xslParentElement.m_parentNode; 
+              }
+           }
+           
+           return  isXslBreakDescendantOfXslIterate;   
+       }       
       
 }
diff --git a/src/org/apache/xalan/templates/ElemIterateNextIteration.java b/src/org/apache/xalan/templates/ElemIterateNextIteration.java
index f8c9ed8c..2e708605 100644
--- a/src/org/apache/xalan/templates/ElemIterateNextIteration.java
+++ b/src/org/apache/xalan/templates/ElemIterateNextIteration.java
@@ -17,12 +17,21 @@
  */
 package org.apache.xalan.templates;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import javax.xml.transform.TransformerException;
 
 import org.apache.xalan.transformer.TransformerImpl;
+import org.apache.xml.utils.QName;
 import org.apache.xpath.Expression;
 import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.VariableStack;
 import org.apache.xpath.XPath;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.XObject;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
 /**
  * XSLT 3.0 xsl:next-iteration element.
@@ -45,6 +54,11 @@ public class ElemIterateNextIteration extends ElemTemplateElement implements Exp
 {
     
      private static final long serialVersionUID = -582877657433106548L;
+     
+     // revisit.
+     // can we have better way to maintain xsl:next-iteration->xsl:with-param* state, instead of having this with
+     // 'public static' visibility.
+     public static List<XslIterateParamWithparamData> fWithparamList = new ArrayList<XslIterateParamWithparamData>();
 
      /**
       * Construct an element representing xsl:next-iteration.
@@ -148,7 +162,28 @@ public class ElemIterateNextIteration extends ElemTemplateElement implements Exp
        */
        public void execute(TransformerImpl transformer) throws TransformerException
        {
-            elemIterateNextIterationProcessing(transformer);
+           
+            XPathContext xpathContext = transformer.getXPathContext();
+  
+            boolean isXslNextIterationDescendantOfXslIterate = false;
+            
+            if (isXslNextIterationDescendantOfXslIterate(this)) {
+                isXslNextIterationDescendantOfXslIterate = true;       
+            }
+            else {
+                throw new TransformerException("XTSE3120 : an xsl:next-iteration instruction doesn't "
+                                                                + "have xsl:iterate instruction as ancestor.", 
+                                                                                       xpathContext.getSAXLocator());  
+            }
+            
+            if (isXslNextIterationDescendantOfXslIterate && isXslInstructionInTailPositionOfSequenceConstructor(this)) {
+                elemIterateNextIterationProcessing(transformer);
+            }
+            else {
+                throw new TransformerException("XTSE3120 : an xsl:next-iteration instruction is not in a "
+                                                                + "tail position within the sequence constructor of currently "
+                                                                + "active xsl:iterate instruction.", xpathContext.getSAXLocator());   
+            }
        }
        
        /**
@@ -160,7 +195,85 @@ public class ElemIterateNextIteration extends ElemTemplateElement implements Exp
         */
         public void elemIterateNextIterationProcessing(TransformerImpl transformer) throws 
                                                                                TransformerException {
-            // no op         
+            
+            XPathContext xctxt = transformer.getXPathContext();
+            
+            int contextNode = xctxt.getContextNode();
+            
+            // clear the, xsl:next-iteration->xsl:with-param* list storage before
+            // evaluating this xsl:next-iteration element.
+            fWithparamList.clear();
+            
+            NodeList nextIterationChildNodes = this.getChildNodes();                        
+            
+            for (int idx = 0; idx < nextIterationChildNodes.getLength(); idx++) {
+                Node nextIterChild = nextIterationChildNodes.item(idx);
+                if (nextIterChild instanceof ElemWithParam) {
+                    ElemWithParam withParamElem = (ElemWithParam)nextIterChild;
+                    QName withParamNameVal = withParamElem.getName();
+                    XPath withParamSelectXPath = withParamElem.getSelect();                              
+                    XslIterateParamWithparamData paramWithparamDataObj = new XslIterateParamWithparamData();
+                    paramWithparamDataObj.setNameVal(withParamNameVal);
+                    paramWithparamDataObj.setSelectVal(withParamSelectXPath);
+                    if (fWithparamList.contains(paramWithparamDataObj)) {
+                        throw new TransformerException("XTSE0670 : duplicate xsl:with-param parameter name '" + withParamNameVal + 
+                                                                                                            "'", xctxt.getSAXLocator());   
+                    }
+                    else {
+                        fWithparamList.add(paramWithparamDataObj);  
+                    }
+                }
+            }
+            
+            if ((ElemIterate.fParamList).size() != fWithparamList.size()) {
+                throw new TransformerException("XTSE0580 : within xsl:iterate, the number of xsl:param elements are not equal to "
+                                                               + "number of xsl:next-iteration's xsl:with-param elements.", xctxt.getSAXLocator());     
+            }
+            else {
+               for (int idx = 0; idx < (ElemIterate.fParamList).size(); idx ++) {
+                   XslIterateParamWithparamData paramData = (ElemIterate.fParamList).get(idx);
+                   XslIterateParamWithparamData withParamData = fWithparamList.get(idx);
+                   if (!(paramData.getNameVal()).equals(withParamData.getNameVal())) {
+                       throw new TransformerException("XTSE3130 : within xsl:iterate, xsl:param and xsl:with-param names at position " + 
+                                                                                              (idx + 1) + " are not same.", xctxt.getSAXLocator());        
+                   }
+               }
+            }
+            
+            VariableStack varStack = xctxt.getVarStack();
+            for (int idx = 0; idx < fWithparamList.size(); idx++) {
+                XslIterateParamWithparamData withParamData = fWithparamList.get(idx);
+                XPath withParamSelectVal = withParamData.getSelectVal();                               
+                XObject evalResult = withParamSelectVal.execute(xctxt, contextNode, this);
+                // update value of current xsl:next-iteration's current xsl:param 
+                // 'parameter'. when xsl:iterate's new iteration is entered, this
+                // parameter shall have this new value.
+                varStack.setLocalVariable(idx, evalResult);
+            }
+        }
+        
+        /*
+         * Determine whether, an xsl:next-iteration instruction has xsl:iterate instruction 
+         * as ancestor. 
+         */
+        private boolean isXslNextIterationDescendantOfXslIterate(ElemIterateNextIteration 
+                                                                                    xslNextInstr) {
+            
+            boolean isXslNextIterationDescendantOfXslIterate = false;
+            
+            ElemTemplateElement xslParentElement = xslNextInstr.m_parentNode;
+            
+            while (xslParentElement != null) {
+               if (xslParentElement instanceof ElemIterate) {
+                   isXslNextIterationDescendantOfXslIterate = true;
+                   break;
+               }
+               else {
+                   xslParentElement = xslParentElement.m_parentNode;    
+               }
+            }
+            
+            return  isXslNextIterationDescendantOfXslIterate;   
         }
       
 }
diff --git a/src/org/apache/xalan/templates/ElemTemplateElement.java b/src/org/apache/xalan/templates/ElemTemplateElement.java
index 9282501b..fcb7f3b6 100644
--- a/src/org/apache/xalan/templates/ElemTemplateElement.java
+++ b/src/org/apache/xalan/templates/ElemTemplateElement.java
@@ -1680,5 +1680,61 @@ public class ElemTemplateElement extends UnImplNode
   public void setGroupNodesDtmHandles(List<Integer> groupNodesDtmHandles) {
       this.fGroupNodesDtmHandles = groupNodesDtmHandles;
   }
+  
+  /*
+   * Method to determine whether, an XSLT instruction is in a sequence constructor's tail position.
+   * 
+   * The XSLT 3.0 spec, provides following definition to determine, whether an XSLT instruction
+   * is in the tail position within an XSLT sequence constructor,
+   * 
+   * An instruction J is in a tail position within a sequence constructor SC if it satisfies 
+   * one of the following conditions:
+     1) J is the last instruction in SC, ignoring any xsl:fallback instructions.
+     2) J is in a tail position within the sequence constructor that forms the body of an xsl:if instruction that 
+        is itself in a tail position within SC.
+     3) J is in a tail position within the sequence constructor that forms the body of an xsl:when or xsl:otherwise 
+        branch of an xsl:choose instruction that is itself in a tail position within SC.
+     4) J is in a tail position within the sequence constructor that forms the body of an xsl:try instruction that 
+        is itself in a tail position within SC (that is, it is immediately followed by an xsl:catch element, ignoring 
+        any xsl:fallback elements).
+     5) J is in a tail position within the sequence constructor that forms the body of an xsl:catch element within 
+        an xsl:try instruction that is itself in a tail position within SC.
+        
+     Notes : Presently, we check only points 1), 2) and 3) as mentioned within previous definition above (excluding 
+             checking the constraints, specified for xsl:fallback instruction).
+             
+     @param  xslInstr    the XSLT instruction for which we need to find, whether its in a tail position of an XSLT 
+                         sequence constructor.                         
+                          
+   */
+  protected boolean isXslInstructionInTailPositionOfSequenceConstructor(ElemTemplateElement xslInstr) {
+      
+      boolean isXslInstructionInTailPositionOfSequenceConstructor = true;
+      
+      ElemTemplateElement elemTemplateElementNextSubling = xslInstr.m_nextSibling;
+      
+      if (elemTemplateElementNextSubling == null) {
+         ElemTemplateElement xslInstrParentElement = xslInstr.m_parentNode;
+          
+         if (xslInstrParentElement instanceof ElemIf) {
+            isXslInstructionInTailPositionOfSequenceConstructor = isXslInstructionInTailPositionOfSequenceConstructor(
+                                                                                             xslInstrParentElement); 
+         }
+         else if ((xslInstrParentElement instanceof ElemWhen) || (xslInstrParentElement 
+                                                                                   instanceof ElemOtherwise)) {
+             xslInstrParentElement = xslInstrParentElement.m_parentNode;
+             isXslInstructionInTailPositionOfSequenceConstructor = isXslInstructionInTailPositionOfSequenceConstructor(
+                                                                                                      xslInstrParentElement);
+         }
+      }
+      else {
+          if (!((elemTemplateElementNextSubling instanceof ElemIterateNextIteration) && 
+                                                                      (elemTemplateElementNextSubling.m_nextSibling == null))) {
+              isXslInstructionInTailPositionOfSequenceConstructor = false;   
+          }
+      }
+      
+      return isXslInstructionInTailPositionOfSequenceConstructor;
+  }
 
 }
diff --git a/src/org/apache/xalan/templates/XslIterateParamWithparamData.java b/src/org/apache/xalan/templates/XslIterateParamWithparamData.java
new file mode 100644
index 00000000..57460d3f
--- /dev/null
+++ b/src/org/apache/xalan/templates/XslIterateParamWithparamData.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.xalan.templates;
+
+import org.apache.xml.utils.QName;
+import org.apache.xpath.XPath;
+
+/**
+ * A class to support evaluation of xsl:iterate instruction.
+         
+   @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+/*
+ * An object of this class, stores information about one xsl:param 
+ * element or one xsl:next-iteration->xsl:with-param element, for a 
+ * particular xsl:iterate instruction.
+ */
+public class XslIterateParamWithparamData {
+    
+    public QName nameVal;
+    
+    public XPath selectVal;
+
+    public QName getNameVal() {
+        return nameVal;
+    }
+
+    public void setNameVal(QName nameVal) {
+        this.nameVal = nameVal;
+    }
+
+    public XPath getSelectVal() {
+        return selectVal;
+    }
+
+    public void setSelectVal(XPath selectVal) {
+        this.selectVal = selectVal;
+    }
+    
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        XslIterateParamWithparamData paramWithparamData = 
+                                                (XslIterateParamWithparamData)obj;
+        return nameVal.equals(paramWithparamData.getNameVal());
+    }
+
+}
diff --git a/tests/org/apache/xalan/xslt3/XslIterateTests.java b/tests/org/apache/xalan/xslt3/XslIterateTests.java
index 48230885..131a2742 100644
--- a/tests/org/apache/xalan/xslt3/XslIterateTests.java
+++ b/tests/org/apache/xalan/xslt3/XslIterateTests.java
@@ -170,5 +170,25 @@ public class XslIterateTests extends XslTransformTestsUtil {
         
         runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
     }
+    
+    @Test
+    public void xslIterateTest13() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_c.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test11.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test11.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslIterateTest14() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_d.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test12.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test12.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
 
 }
diff --git a/tests/xsl_iterate/gold/test11.out b/tests/xsl_iterate/gold/test11.out
new file mode 100644
index 00000000..16aa07e6
--- /dev/null
+++ b/tests/xsl_iterate/gold/test11.out
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?><account>
+  <balance value="12.00" date="2008-09-01"/>
+  <balance value="20.00" date="2008-09-01"/>
+  <balance value="18.00" date="2008-09-02"/>
+  <balance value="23.00" date="2008-09-02"/>
+</account>
diff --git a/tests/xsl_iterate/gold/test12.out b/tests/xsl_iterate/gold/test12.out
new file mode 100644
index 00000000..c6406da2
--- /dev/null
+++ b/tests/xsl_iterate/gold/test12.out
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <total value="12.00" sequence="1"/>
+  <total value="10.00" sequence="1"/>
+  <total value="13.00" sequence="1"/>
+</result>
diff --git a/tests/xsl_iterate/iterate-003.xsl b/tests/xsl_iterate/iterate-003.xsl
index 83c9e36a..656c8bd3 100644
--- a/tests/xsl_iterate/iterate-003.xsl
+++ b/tests/xsl_iterate/iterate-003.xsl
@@ -29,7 +29,7 @@
           </xsl:otherwise>
         </xsl:choose>
         <xsl:next-iteration>
-	   <xsl:with-param name="basketCost" select="$basketCost + PRICE"/>
+	       <xsl:with-param name="basketCost" select="$basketCost + PRICE"/>
         </xsl:next-iteration>
       </xsl:iterate>
     </out>
diff --git a/tests/xsl_iterate/iterate-003.xsl b/tests/xsl_iterate/test11.xsl
similarity index 50%
copy from tests/xsl_iterate/iterate-003.xsl
copy to tests/xsl_iterate/test11.xsl
index 83c9e36a..6e182794 100644
--- a/tests/xsl_iterate/iterate-003.xsl
+++ b/tests/xsl_iterate/test11.xsl
@@ -1,38 +1,29 @@
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                 version="3.0">
                 
-  <!-- use with iterate001.xml -->
+  <!-- Author: mukulg@apache.org -->
    
-  <!-- An XSLT stylesheet test case, that uses xsl:iterate 
-       along with xsl:param and xsl:next-iteration. This
-       XSLT stylesheet uses xsl:break instruction to exit
-       from xsl:iterate loop early.  
+  <!-- use with test1_c.xml -->
+   
+  <!-- This XSLT stylesheet, uses xsl:iterate to compute cumulative 
+       totals.
        
-       This XSLT stylesheet has been borrowed from W3C XSLT 
-       3.0 test suite and makes few changes to XSLT stylesheet 
-       syntax. -->
-        
-  <xsl:output method="xml" indent="yes"/>                
+       This XSLT stylesheet is borrowed from XSLT 3.0 spec, with 
+       slight modifications. -->                 
+  
+  <xsl:output method="xml" indent="yes"/>
 
   <xsl:template match="/">
-    <out>
-      <xsl:iterate select="//ITEM">
-        <xsl:param name="basketCost" select="0"/>
-        <xsl:choose>
-          <xsl:when test="$basketCost &gt; 12.00">
-            <xsl:break/>
-          </xsl:when>
-          <xsl:otherwise>
-            <item cost="{format-number($basketCost, '00.00')}">
-              <xsl:copy-of select="TITLE"/>
-            </item>            
-          </xsl:otherwise>
-        </xsl:choose>
-        <xsl:next-iteration>
-	   <xsl:with-param name="basketCost" select="$basketCost + PRICE"/>
-        </xsl:next-iteration>
-      </xsl:iterate>
-    </out>
+     <account>
+        <xsl:iterate select="transactions/transaction">
+          <xsl:param name="balance" select="0.00"/>
+          <xsl:variable name="newBalance" select="$balance + @value"/>
+          <balance date="{@date}" value="{format-number($newBalance, '0.00')}"/>
+          <xsl:next-iteration>
+             <xsl:with-param name="balance" select="$newBalance"/>
+          </xsl:next-iteration>
+        </xsl:iterate>
+     </account>
   </xsl:template>
   
   <!--
diff --git a/tests/xsl_iterate/test12.xsl b/tests/xsl_iterate/test12.xsl
new file mode 100644
index 00000000..331602b4
--- /dev/null
+++ b/tests/xsl_iterate/test12.xsl
@@ -0,0 +1,62 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
+                version="3.0">
+                
+  <!-- Author: mukulg@apache.org -->
+   
+  <!-- use with test1_d.xml -->
+   
+  <!-- An XSLT stylesheet test case, that uses xsl:iterate and xsl:next-iteration. 
+       The xsl:next-iteration instruction is specified in a tail position (as per 
+       definition of, when an XSLT instruction is in a sequence constructor's tail 
+       position) of sequence constructor that is a child of xsl:iterate.
+       
+       Using xsl:iterate, this stylesheet reads a sequence of 'a' elements, and breaks
+       from xsl:iterate when value of 'sequence' attribute changes for the first time.
+       This stylesheet also, maintains and outputs cumulative total of attribute 
+       'value'. -->                 
+  
+  <xsl:output method="xml" indent="yes"/>
+
+  <xsl:template match="/elem">
+     <result>
+        <xsl:iterate select="a">
+	       <xsl:param name="total" select="0.00"/>
+	       <xsl:param name="prevSequence" select="0"/>	   
+	       <xsl:variable name="newTotal" select="$total + @value"/>
+	       <xsl:variable name="thisSequence" select="@sequence"/>	   
+	       <xsl:choose>
+	          <xsl:when test="(position() = 1) or ($thisSequence = $prevSequence)">
+	             <total sequence="{$thisSequence}"
+	                    value="{format-number($newTotal, '0.00')}"/>
+	             <xsl:next-iteration>
+	                <xsl:with-param name="total" select="$newTotal"/>
+	                <xsl:with-param name="prevSequence" select="$thisSequence"/>
+	             </xsl:next-iteration>	        
+	          </xsl:when>
+	          <xsl:otherwise>
+	             <xsl:break/>
+	          </xsl:otherwise>
+	       </xsl:choose>
+        </xsl:iterate>
+      </result>
+  </xsl:template>
+  
+  <!--
+      * Licensed to the Apache Software Foundation (ASF) under one
+      * or more contributor license agreements. See the NOTICE file
+      * distributed with this work for additional information
+      * regarding copyright ownership. The ASF licenses this file
+      * to you under the Apache License, Version 2.0 (the  "License");
+      * you may not use this file except in compliance with the License.
+      * You may obtain a copy of the License at
+      *
+      *     http://www.apache.org/licenses/LICENSE-2.0
+      *
+      * Unless required by applicable law or agreed to in writing, software
+      * distributed under the License is distributed on an "AS IS" BASIS,
+      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      * See the License for the specific language governing permissions and
+      * limitations under the License.
+  -->
+
+</xsl:stylesheet>
diff --git a/tests/xsl_iterate/test1_c.xml b/tests/xsl_iterate/test1_c.xml
new file mode 100644
index 00000000..4a69a814
--- /dev/null
+++ b/tests/xsl_iterate/test1_c.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<transactions>
+  <transaction date="2008-09-01" value="12.00"/>
+  <transaction date="2008-09-01" value="8.00"/>
+  <transaction date="2008-09-02" value="-2.00"/>
+  <transaction date="2008-09-02" value="5.00"/>
+</transactions>
\ No newline at end of file
diff --git a/tests/xsl_iterate/test1_d.xml b/tests/xsl_iterate/test1_d.xml
new file mode 100644
index 00000000..80a2ae4d
--- /dev/null
+++ b/tests/xsl_iterate/test1_d.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<elem>
+  <a sequence="1" value="12.00"/>
+  <a sequence="1" value="-2.00"/>
+  <a sequence="1" value="3.00"/>
+  <a sequence="2" value="4.00"/>
+  <a sequence="2" value="5.00"/>
+</elem>
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xalan.apache.org
For additional commands, e-mail: commits-help@xalan.apache.org