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/09/30 12:11:01 UTC
[xalan-java] branch xalan-j_xslt3.0 updated: committing improvements to implementation of xslt 3.0's xsl:iterate instruction, making it more correct. also committing few new working related test cases.
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 0e3d0cae committing improvements to implementation of xslt 3.0's xsl:iterate instruction, making it more correct. also committing few new working related test cases.
new 6c3babb1 Merge pull request #92 from mukulga/xalan-j_xslt3.0_mukul
0e3d0cae is described below
commit 0e3d0cae9c83771f55fb73be4361b3c189cfb3bf
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Sat Sep 30 17:36:40 2023 +0530
committing improvements to implementation of xslt 3.0's xsl:iterate instruction, making it more correct. also committing few new working related test cases.
---
src/org/apache/xalan/templates/ElemIterate.java | 297 ++++++++++-----------
.../apache/xalan/templates/ElemIterateBreak.java | 20 +-
.../xalan/templates/ElemIterateNextIteration.java | 137 +++++++---
.../xalan/templates/ElemIterateOnCompletion.java | 41 ++-
src/org/apache/xalan/templates/ElemParam.java | 47 ++--
.../apache/xalan/transformer/TransformerImpl.java | 26 ++
.../xslt/util/XslTransformSharedDatastore.java | 6 -
tests/org/apache/xalan/xslt3/XslIterateTests.java | 40 +++
tests/xsl_iterate/gold/test23.out | 4 +
tests/xsl_iterate/gold/test24.out | 9 +
tests/xsl_iterate/gold/test25.out | 4 +
tests/xsl_iterate/gold/test26.out | 9 +
tests/xsl_iterate/test1_g.xml | 4 +
tests/xsl_iterate/test23.xsl | 64 +++++
tests/xsl_iterate/test24.xsl | 72 +++++
tests/xsl_iterate/test25.xsl | 69 +++++
tests/xsl_iterate/test26.xsl | 75 ++++++
17 files changed, 666 insertions(+), 258 deletions(-)
diff --git a/src/org/apache/xalan/templates/ElemIterate.java b/src/org/apache/xalan/templates/ElemIterate.java
index 62765e9a..8e767d36 100644
--- a/src/org/apache/xalan/templates/ElemIterate.java
+++ b/src/org/apache/xalan/templates/ElemIterate.java
@@ -23,7 +23,6 @@ import java.util.List;
import javax.xml.transform.TransformerException;
import org.apache.xalan.transformer.TransformerImpl;
-import org.apache.xalan.xslt.util.XslTransformSharedDatastore;
import org.apache.xml.dtm.DTM;
import org.apache.xml.dtm.DTMIterator;
import org.apache.xml.utils.IntStack;
@@ -32,42 +31,19 @@ import org.apache.xpath.Expression;
import org.apache.xpath.ExpressionOwner;
import org.apache.xpath.XPath;
import org.apache.xpath.XPathContext;
-import org.apache.xpath.functions.DynamicFunctionCall;
-import org.apache.xpath.functions.Function;
import org.apache.xpath.objects.ResultSequence;
import org.apache.xpath.objects.XNodeSet;
import org.apache.xpath.objects.XObject;
-import org.apache.xpath.operations.Operation;
-import org.apache.xpath.operations.Variable;
-/**
- * XSLT 3.0 xsl:iterate element.
+/*
+ * Implementation of the XSLT 3.0 xsl:iterate instruction.
*
- <xsl:iterate select = expression>
- <!-- Content: (xsl:param*, xsl:on-completion?, sequence-constructor) -->
- </xsl:iterate>
-
- <xsl:next-iteration>
- <!-- Content: (xsl:with-param*) -->
- </xsl:next-iteration>
-
- <xsl:break select? = expression>
- <!-- Content: sequence-constructor -->
- </xsl:break>
-
- <xsl:on-completion select? = expression>
- <!-- Content: sequence-constructor -->
- </xsl:on-completion>
-
- Ref : https://www.w3.org/TR/xslt-30/#iterate
-
- @author Mukul Gandhi <mu...@apache.org>
+ * Ref : https://www.w3.org/TR/xslt-30/#element-iterate
+ *
+ * @author Mukul Gandhi <mu...@apache.org>
*
* @xsl.usage advanced
*/
-/*
- * Implementation of the XSLT 3.0 xsl:iterate instruction.
- */
public class ElemIterate extends ElemTemplateElement implements ExpressionOwner
{
@@ -190,9 +166,7 @@ public class ElemIterate extends ElemTemplateElement implements ExpressionOwner
*
* @xsl.usage advanced
*/
- public void transformSelectedNodes(TransformerImpl transformer) throws TransformerException {
-
- final XPathContext xctxtOriginal = transformer.getXPathContext();
+ private void transformSelectedNodes(TransformerImpl transformer) throws TransformerException {
XPathContext xctxt = transformer.getXPathContext();
@@ -202,154 +176,163 @@ public class ElemIterate extends ElemTemplateElement implements ExpressionOwner
// instruction's evaluation.
fXslIterateParamWithparamDataList.clear();
- validateXslElemIterateChildElementsSequence(xctxt);
-
- // Evaluate xsl:iterate instruction, when value of its "select" attribute evaluates
- // to a 'ResultSequence'.
- if ((m_selectExpression instanceof Variable) ||
- (m_selectExpression instanceof Operation) ||
- (m_selectExpression instanceof Function) ||
- (m_selectExpression instanceof DynamicFunctionCall)) {
+ validateXslElemIterateChildElementsSequence(xctxt);
- XObject evalResult = m_selectExpression.execute(xctxt);
+ XObject evalResult = m_selectExpression.execute(xctxt);
- if (evalResult instanceof ResultSequence) {
- ResultSequence resultSeq = (ResultSequence)evalResult;
- List<XObject> resultSeqItems = resultSeq.getResultSequenceItems();
+ if (evalResult instanceof ResultSequence) {
+ ResultSequence resultSeq = (ResultSequence)evalResult;
+ List<XObject> resultSeqItems = resultSeq.getResultSequenceItems();
- ElemIterateOnCompletion xslOnCompletionTemplate = null;
+ ElemIterateOnCompletion xslOnCompletionTemplate = null;
- for (int idx = 0; idx < resultSeqItems.size(); idx++) {
- XObject resultSeqItem = resultSeqItems.get(idx);
-
- if (resultSeqItem instanceof XNodeSet) {
- resultSeqItem = ((XNodeSet)resultSeqItem).getFresh();
- }
-
- setXPathContextForXslSequenceProcessing(resultSeqItems.size(), idx, resultSeqItem, xctxt);
-
- boolean isBreakFromXslContentLoop = false;
+ boolean isBreakFromXslContentLoop = false;
+
+ for (int idx = 0; idx < resultSeqItems.size(); idx++) {
+ XObject resultSeqItem = resultSeqItems.get(idx);
- for (ElemTemplateElement elemTemplate = this.m_firstChild; elemTemplate != null;
- elemTemplate = elemTemplate.m_nextSibling) {
- if ((elemTemplate instanceof ElemIterateOnCompletion) && (xslOnCompletionTemplate == null)) {
- xslOnCompletionTemplate = (ElemIterateOnCompletion)elemTemplate;
- }
-
- if (!(XslTransformSharedDatastore.isXslIterateBreakEvaluated).booleanValue()) {
- xctxt.setSAXLocator(elemTemplate);
- transformer.setCurrentElement(elemTemplate);
- elemTemplate.execute(transformer);
- }
- else {
- resetXPathContextForXslSequenceProcessing(resultSeqItem, xctxt);
- isBreakFromXslContentLoop = true;
- break;
- }
- }
+ if (resultSeqItem instanceof XNodeSet) {
+ resultSeqItem = ((XNodeSet)resultSeqItem).getFresh();
+ }
- if (!isBreakFromXslContentLoop) {
- resetXPathContextForXslSequenceProcessing(resultSeqItem, xctxt);
- }
+ setXPathContextForXslSequenceProcessing(resultSeqItems.size(), idx, resultSeqItem, xctxt);
+
+ for (ElemTemplateElement elemTemplate = this.m_firstChild; elemTemplate != null;
+ elemTemplate = elemTemplate.m_nextSibling) {
+ if (idx == 0) {
+ if (elemTemplate instanceof ElemParam) {
+ // For xsl:iterate's first iteration, evaluate xsl:param element
+ xctxt.setSAXLocator(elemTemplate);
+ transformer.setCurrentElement(elemTemplate);
+ ((ElemParam)elemTemplate).setXslIterateIterationIdx(idx);
+ elemTemplate.execute(transformer);
+ }
+ else if (elemTemplate instanceof ElemIterateOnCompletion) {
+ xslOnCompletionTemplate = (ElemIterateOnCompletion)elemTemplate;
+ }
+ else {
+ if (!transformer.isXslIterateBreakEvaluated()) {
+ xctxt.setSAXLocator(elemTemplate);
+ transformer.setCurrentElement(elemTemplate);
+ elemTemplate.execute(transformer);
+ }
+ else {
+ resetXPathContextForXslSequenceProcessing(resultSeqItem, xctxt);
+ isBreakFromXslContentLoop = true;
+ break;
+ }
+ }
+ }
+ else {
+ if (!transformer.isXslIterateBreakEvaluated()) {
+ xctxt.setSAXLocator(elemTemplate);
+ transformer.setCurrentElement(elemTemplate);
+ elemTemplate.execute(transformer);
+ }
+ else {
+ resetXPathContextForXslSequenceProcessing(resultSeqItem, xctxt);
+ isBreakFromXslContentLoop = true;
+ break;
+ }
+ }
+ }
- if ((XslTransformSharedDatastore.isXslIterateBreakEvaluated).booleanValue()) {
- break;
- }
- }
+ if (!isBreakFromXslContentLoop) {
+ resetXPathContextForXslSequenceProcessing(resultSeqItem, xctxt);
+ }
+ else {
+ break;
+ }
+ }
- // Reset the, XPath context's size, item and position variables
- xctxt.setXPath3ContextSize(-1);
- xctxt.setXPath3ContextItem(null);
- xctxt.setXPath3ContextPosition(-1);
+ // Reset the, XPath context's size, item and position variables
+ xctxt.setXPath3ContextSize(-1);
+ xctxt.setXPath3ContextItem(null);
+ xctxt.setXPath3ContextPosition(-1);
- if ((xslOnCompletionTemplate != null) && !(XslTransformSharedDatastore.
- isXslIterateBreakEvaluated).booleanValue()) {
- XslTransformSharedDatastore.isXslIterateOnCompletionActive = Boolean.TRUE;
- xctxt.setSAXLocator(xslOnCompletionTemplate);
- transformer.setCurrentElement(xslOnCompletionTemplate);
- xslOnCompletionTemplate.execute(transformer);
- XslTransformSharedDatastore.isXslIterateOnCompletionActive = Boolean.FALSE;
- }
-
- XslTransformSharedDatastore.isXslIterateBreakEvaluated = Boolean.FALSE;
-
- transformer.setXPathContext(xctxtOriginal);
-
- // return from this xsl:iterate instruction's evaluation
- return;
+ if ((xslOnCompletionTemplate != null) && !transformer.isXslIterateBreakEvaluated()) {
+ transformer.setXslIterateOnCompletionActive(true);
+ xctxt.setSAXLocator(xslOnCompletionTemplate);
+ transformer.setCurrentElement(xslOnCompletionTemplate);
+ xslOnCompletionTemplate.execute(transformer);
+ transformer.setXslIterateOnCompletionActive(false);
}
+
+ transformer.setXslIterateBreakEvaluated(false);
}
-
- // Evaluate xsl:iterate instruction, when value of its "select" attribute evaluates
- // to a node set.
- DTMIterator sourceNodes = m_selectExpression.asIterator(xctxt, sourceNode);
+ else {
+ // Evaluate xsl:iterate instruction, when value of its "select" attribute evaluates
+ // to a node set.
+ DTMIterator sourceNodes = m_selectExpression.asIterator(xctxt, sourceNode);
- try {
- xctxt.pushCurrentNode(DTM.NULL);
-
- IntStack currentNodes = xctxt.getCurrentNodeStack();
-
- xctxt.pushCurrentExpressionNode(DTM.NULL);
-
- IntStack currentExpressionNodes = xctxt.getCurrentExpressionNodeStack();
-
- xctxt.pushSAXLocatorNull();
- xctxt.pushContextNodeList(sourceNodes);
- transformer.pushElemTemplateElement(null);
+ try {
+ xctxt.pushCurrentNode(DTM.NULL);
+ IntStack currentNodes = xctxt.getCurrentNodeStack();
+ xctxt.pushCurrentExpressionNode(DTM.NULL);
+ IntStack currentExpressionNodes = xctxt.getCurrentExpressionNodeStack();
+ xctxt.pushSAXLocatorNull();
+ xctxt.pushContextNodeList(sourceNodes);
+ transformer.pushElemTemplateElement(null);
- int nextNode;
+ int nextNode;
- ElemIterateOnCompletion xslOnCompletionTemplate = null;
+ ElemIterateOnCompletion xslOnCompletionTemplate = null;
- while ((nextNode = sourceNodes.nextNode()) != DTM.NULL) {
- currentNodes.setTop(nextNode);
- currentExpressionNodes.setTop(nextNode);
+ int idx = -1;
+ while ((nextNode = sourceNodes.nextNode()) != DTM.NULL) {
+ idx++;
+ currentNodes.setTop(nextNode);
+ currentExpressionNodes.setTop(nextNode);
- for (ElemTemplateElement elemTemplate = this.m_firstChild; elemTemplate != null;
+ for (ElemTemplateElement elemTemplate = this.m_firstChild; elemTemplate != null;
elemTemplate = elemTemplate.m_nextSibling) {
- if ((elemTemplate instanceof ElemIterateOnCompletion) &&
+ if ((elemTemplate instanceof ElemIterateOnCompletion) &&
(xslOnCompletionTemplate == null)) {
- xslOnCompletionTemplate = (ElemIterateOnCompletion)elemTemplate;
- }
+ xslOnCompletionTemplate = (ElemIterateOnCompletion)elemTemplate;
+ }
- if (!(XslTransformSharedDatastore.isXslIterateBreakEvaluated).booleanValue()) {
- xctxt.setSAXLocator(elemTemplate);
- transformer.setCurrentElement(elemTemplate);
- elemTemplate.execute(transformer);
- }
- else {
- break;
- }
- }
+ if ((idx == 0) && (elemTemplate instanceof ElemParam)) {
+ xctxt.setSAXLocator(elemTemplate);
+ transformer.setCurrentElement(elemTemplate);
+ ((ElemParam)elemTemplate).setXslIterateIterationIdx(idx);
+ elemTemplate.execute(transformer);
+ }
+ else {
+ if (!transformer.isXslIterateBreakEvaluated()) {
+ xctxt.setSAXLocator(elemTemplate);
+ transformer.setCurrentElement(elemTemplate);
+ elemTemplate.execute(transformer);
+ }
+ else {
+ break;
+ }
+ }
+ }
- if ((XslTransformSharedDatastore.isXslIterateBreakEvaluated).booleanValue()) {
- break;
+ if (transformer.isXslIterateBreakEvaluated()) {
+ break;
+ }
}
- }
- if ((xslOnCompletionTemplate != null) && !(XslTransformSharedDatastore.
- isXslIterateBreakEvaluated).booleanValue()) {
- XslTransformSharedDatastore.isXslIterateOnCompletionActive = Boolean.TRUE;
- xctxt.setSAXLocator(xslOnCompletionTemplate);
- transformer.setCurrentElement(xslOnCompletionTemplate);
- xslOnCompletionTemplate.execute(transformer);
- XslTransformSharedDatastore.isXslIterateOnCompletionActive = Boolean.FALSE;
- }
+ if ((xslOnCompletionTemplate != null) && !transformer.isXslIterateBreakEvaluated()) {
+ transformer.setXslIterateOnCompletionActive(true);
+ xctxt.setSAXLocator(xslOnCompletionTemplate);
+ transformer.setCurrentElement(xslOnCompletionTemplate);
+ xslOnCompletionTemplate.execute(transformer);
+ transformer.setXslIterateOnCompletionActive(false);
+ }
- XslTransformSharedDatastore.isXslIterateBreakEvaluated = Boolean.FALSE;
- }
- finally {
- xctxt.popSAXLocator();
- xctxt.popContextNodeList();
- transformer.popElemTemplateElement();
- xctxt.popCurrentExpressionNode();
- xctxt.popCurrentNode();
- sourceNodes.detach();
- }
-
- // Restore the xpath context, to where it was before this xsl:iterate
- // instruction began an evaluation.
- transformer.setXPathContext(xctxtOriginal);
+ transformer.setXslIterateBreakEvaluated(false);
+ }
+ finally {
+ xctxt.popSAXLocator();
+ xctxt.popContextNodeList();
+ transformer.popElemTemplateElement();
+ xctxt.popCurrentExpressionNode();
+ xctxt.popCurrentNode();
+ sourceNodes.detach();
+ }
+ }
}
/**
diff --git a/src/org/apache/xalan/templates/ElemIterateBreak.java b/src/org/apache/xalan/templates/ElemIterateBreak.java
index c2df8afc..e8eee619 100644
--- a/src/org/apache/xalan/templates/ElemIterateBreak.java
+++ b/src/org/apache/xalan/templates/ElemIterateBreak.java
@@ -20,7 +20,6 @@ package org.apache.xalan.templates;
import javax.xml.transform.TransformerException;
import org.apache.xalan.transformer.TransformerImpl;
-import org.apache.xalan.xslt.util.XslTransformSharedDatastore;
import org.apache.xml.serializer.SerializationHandler;
import org.apache.xpath.Expression;
import org.apache.xpath.ExpressionOwner;
@@ -28,21 +27,14 @@ import org.apache.xpath.XPath;
import org.apache.xpath.XPathContext;
import org.xml.sax.SAXException;
-/**
- * XSLT 3.0 xsl:break element.
- *
- <xsl:break select? = expression>
- <!-- Content: sequence-constructor -->
- </xsl:break>
-
- @author Mukul Gandhi <mu...@apache.org>
- *
- * @xsl.usage advanced
- */
/*
* Implementation of the XSLT 3.0 xsl:break instruction.
*
- * The XSLT xsl:break element is intended to be used, within xsl:iterate element.
+ * Ref : https://www.w3.org/TR/xslt-30/#element-iterate
+ *
+ * @author Mukul Gandhi <mu...@apache.org>
+ *
+ * @xsl.usage advanced
*/
public class ElemIterateBreak extends ElemTemplateElement implements ExpressionOwner
{
@@ -169,7 +161,7 @@ public class ElemIterateBreak extends ElemTemplateElement implements ExpressionO
if (isXslBreakDescendantOfXslIterate && isXslInstructionInTailPositionOfSequenceConstructor(this)) {
transformXslBreakInstruction(transformer);
- XslTransformSharedDatastore.isXslIterateBreakEvaluated = Boolean.TRUE;
+ transformer.setXslIterateBreakEvaluated(true);
}
else {
throw new TransformerException("XTSE3120 : an xsl:break instruction is not in a "
diff --git a/src/org/apache/xalan/templates/ElemIterateNextIteration.java b/src/org/apache/xalan/templates/ElemIterateNextIteration.java
index 3ceaa4ad..23a35516 100644
--- a/src/org/apache/xalan/templates/ElemIterateNextIteration.java
+++ b/src/org/apache/xalan/templates/ElemIterateNextIteration.java
@@ -33,31 +33,20 @@ import org.apache.xpath.objects.XObject;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-/**
- * XSLT 3.0 xsl:next-iteration element.
- *
- <xsl:next-iteration>
- <!-- Content: (xsl:with-param*) -->
- </xsl:next-iteration>
-
- @author Mukul Gandhi <mu...@apache.org>
- *
- * @xsl.usage advanced
- */
/*
* Implementation of the XSLT 3.0 xsl:next-iteration instruction.
*
- * The XSLT xsl:next-iteration element is intended to be used, within
- * xsl:iterate element.
+ * Ref : https://www.w3.org/TR/xslt-30/#element-iterate
+ *
+ * @author Mukul Gandhi <mu...@apache.org>
+ *
+ * @xsl.usage advanced
*/
public class ElemIterateNextIteration extends ElemTemplateElement implements ExpressionOwner
{
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>();
/**
@@ -164,25 +153,20 @@ public class ElemIterateNextIteration extends ElemTemplateElement implements Exp
{
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(this)) {
+ throw new TransformerException("XTSE3120 : An xsl:next-iteration instruction doesn't "
+ + "have xsl:iterate instruction as an ancestor.",
+ xpathContext.getSAXLocator());
}
- if (isXslNextIterationDescendantOfXslIterate && isXslInstructionInTailPositionOfSequenceConstructor(this)) {
+ if (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());
+ + "tail position within the sequence constructor of currently "
+ + "active xsl:iterate instruction.", xpathContext.getSAXLocator());
}
}
@@ -193,14 +177,14 @@ public class ElemIterateNextIteration extends ElemTemplateElement implements Exp
*
* @xsl.usage advanced
*/
- public void elemIterateNextIterationProcessing(TransformerImpl transformer) throws
- TransformerException {
+ private void elemIterateNextIterationProcessing(TransformerImpl transformer) throws
+ TransformerException {
XPathContext xctxt = transformer.getXPathContext();
int contextNode = xctxt.getContextNode();
- // clear the, xsl:next-iteration->xsl:with-param* list storage before
+ // Clear the, xsl:next-iteration->xsl:with-param* list storage before
// evaluating this xsl:next-iteration element.
fWithparamList.clear();
@@ -227,7 +211,7 @@ public class ElemIterateNextIteration extends ElemTemplateElement implements Exp
if ((ElemIterate.fXslIterateParamWithparamDataList).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());
+ + "number of xsl:next-iteration's xsl:with-param elements.", xctxt.getSAXLocator());
}
else {
for (int idx = 0; idx < (ElemIterate.fXslIterateParamWithparamDataList).size(); idx ++) {
@@ -235,23 +219,100 @@ public class ElemIterateNextIteration extends ElemTemplateElement implements Exp
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());
+ (idx + 1) + " are not same.", xctxt.getSAXLocator());
}
}
}
+ // Update all of xsl:iterate's xsl:param values, using the corresponding
+ // xsl:next-iteration's xsl:with-param values. The code within 'for' loop below,
+ // updates each of the xsl:iterate->xsl:param's values for xsl:iterate's second and
+ // greater iterations. For xsl:iterate's first iteration, xsl:param's get their
+ // values from the xsl:param instructions themselves.
VariableStack varStack = xctxt.getVarStack();
for (int idx = 0; idx < fWithparamList.size(); idx++) {
XslIterateParamWithparamData withParamData = fWithparamList.get(idx);
+
+ QName xslParamQName = withParamData.getNameVal();
+ ElemParam elemParam = getElemParamForQName(xslParamQName);
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);
+ XObject withParamVal = withParamSelectVal.execute(xctxt, contextNode, this);
+ varStack.setLocalVariable(elemParam.getIndex(), withParamVal);
}
}
+ /*
+ * For the currently active xsl:next-iteration instruction, find reference to
+ * its xsl:iterate->xsl:param element for a given xsl:iterate->xsl:param's name.
+ *
+ * We find this xsl:param element reference, by xsl element traversal on
+ * preceding-sibling and ancestor axes directions starting from the current
+ * xsl:next-iteration instruction.
+ *
+ * This method shall always find, an eligible non-null xsl:iterate->xsl:param
+ * element reference for a given xsl:iterate->xsl:param's name.
+ */
+ private ElemParam getElemParamForQName(QName xslParamQName) {
+ ElemParam elemParam = null;
+
+ // First, we search for the desired xsl:param element on the preceding-sibling
+ // axis direction.
+ ElemTemplateElement prevSibling = (ElemTemplateElement)getPreviousSibling();
+ while (prevSibling != null) {
+ if (prevSibling instanceof ElemParam) {
+ ElemParam elemParamTemp = (ElemParam)prevSibling;
+ if ((elemParamTemp.getName()).equals(xslParamQName)) {
+ elemParam = elemParamTemp;
+ break;
+ }
+ else {
+ prevSibling = (ElemTemplateElement)(prevSibling.getPreviousSibling());
+ }
+ }
+ else {
+ prevSibling = (ElemTemplateElement)(prevSibling.getPreviousSibling());
+ }
+ }
+
+ // The desired xsl:param element was not found, on the preceding-sibling axis
+ // direction. Now, we attempt a new search for desired xsl:param element
+ // on the ancestor axis direction.
+ if (elemParam == null) {
+ ElemTemplateElement parentElem = getParentElem();
+ while (parentElem != null) {
+ if (parentElem instanceof ElemIterate) {
+ ElemTemplateElement elemIterateChild = (ElemTemplateElement)(parentElem.getFirstChild());
+ boolean isToBreakFromCheck = false;
+ while (elemIterateChild != null) {
+ if (elemIterateChild instanceof ElemParam) {
+ ElemParam elemParamTemp = (ElemParam)elemIterateChild;
+ if ((elemParamTemp.getName()).equals(xslParamQName)) {
+ elemParam = elemParamTemp;
+ isToBreakFromCheck = true;
+ break;
+ }
+ else {
+ elemIterateChild = elemIterateChild.getNextSiblingElem();
+ }
+ }
+ else {
+ elemIterateChild = elemIterateChild.getNextSiblingElem();
+ }
+ }
+
+ if (isToBreakFromCheck) {
+ break;
+ }
+ }
+ else {
+ parentElem = parentElem.getParentElem();
+ }
+ }
+ }
+
+ return elemParam;
+ }
+
/*
* Determine whether, an xsl:next-iteration instruction has xsl:iterate instruction
* as ancestor.
diff --git a/src/org/apache/xalan/templates/ElemIterateOnCompletion.java b/src/org/apache/xalan/templates/ElemIterateOnCompletion.java
index 1e51ed95..781d7bf0 100644
--- a/src/org/apache/xalan/templates/ElemIterateOnCompletion.java
+++ b/src/org/apache/xalan/templates/ElemIterateOnCompletion.java
@@ -20,7 +20,6 @@ package org.apache.xalan.templates;
import javax.xml.transform.TransformerException;
import org.apache.xalan.transformer.TransformerImpl;
-import org.apache.xalan.xslt.util.XslTransformSharedDatastore;
import org.apache.xml.serializer.SerializationHandler;
import org.apache.xpath.Expression;
import org.apache.xpath.ExpressionOwner;
@@ -30,22 +29,14 @@ import org.xml.sax.SAXException;
import com.sun.org.apache.xml.internal.dtm.DTM;
-/**
- * XSLT 3.0 xsl:on-completion element.
- *
- <xsl:on-completion select? = expression>
- <!-- Content: sequence-constructor -->
- </xsl:on-completion>
-
- @author Mukul Gandhi <mu...@apache.org>
- *
- * @xsl.usage advanced
- */
/*
* Implementation of the XSLT 3.0 xsl:on-completion instruction.
*
- * The XSLT xsl:on-completion element is intended to be used, within
- * xsl:iterate element.
+ * Ref : https://www.w3.org/TR/xslt-30/#element-iterate
+ *
+ * @author Mukul Gandhi <mu...@apache.org>
+ *
+ * @xsl.usage advanced
*/
public class ElemIterateOnCompletion extends ElemTemplateElement implements ExpressionOwner
{
@@ -167,16 +158,15 @@ public class ElemIterateOnCompletion extends ElemTemplateElement implements Expr
*
* @xsl.usage advanced
*/
- public void transformXslOncompletionInstruction(TransformerImpl transformer) throws
- TransformerException {
+ private void transformXslOncompletionInstruction(TransformerImpl transformer)
+ throws TransformerException {
- if ((XslTransformSharedDatastore.isXslIterateOnCompletionActive).booleanValue()) {
- final XPathContext originalXctxt = transformer.getXPathContext();
-
+ if (transformer.isXslIterateOnCompletionActive()) {
XPathContext xctxt = transformer.getXPathContext();
- // during evaluation of xsl:on-completion, the context item is absent.
- // we make following two changes to XPath context to ensure this.
+ // During evaluation of xsl:on-completion instruction, the XPath context item
+ // is absent. We make following two changes to an active XPath context to
+ // ensure this.
xctxt.pushCurrentNode(DTM.NULL);
xctxt.pushCurrentExpressionNode(DTM.NULL);
@@ -185,9 +175,11 @@ public class ElemIterateOnCompletion extends ElemTemplateElement implements Expr
try {
m_selectExpression.executeCharsToContentHandler(xctxt, rth);
- } catch (TransformerException ex) {
+ }
+ catch (TransformerException ex) {
throw ex;
- } catch (SAXException ex) {
+ }
+ catch (SAXException ex) {
throw new TransformerException(ex);
}
}
@@ -199,9 +191,6 @@ public class ElemIterateOnCompletion extends ElemTemplateElement implements Expr
elemTemplate.execute(transformer);
}
}
-
- // restore the XPath original context, on current XSLT transformer object
- transformer.setXPathContext(originalXctxt);
}
}
diff --git a/src/org/apache/xalan/templates/ElemParam.java b/src/org/apache/xalan/templates/ElemParam.java
index bf4033ca..d9273360 100644
--- a/src/org/apache/xalan/templates/ElemParam.java
+++ b/src/org/apache/xalan/templates/ElemParam.java
@@ -42,9 +42,15 @@ public class ElemParam extends ElemVariable
static final long serialVersionUID = -1131781475589006431L;
int m_qnameID;
+
+ /**
+ * This class field, supports evaluation of stylesheet
+ * xsl:iterate->xsl:param elements.
+ */
+ private int xslIterateIterationIdx = -1;
/**
- * Constructor ElemParam
+ * Constructor ElemParam.
*
*/
public ElemParam(){}
@@ -117,27 +123,27 @@ public class ElemParam extends ElemVariable
SourceLocator srcLocator = xctx.getSAXLocator();
- String asAttrVal = getAs();
+ boolean isChildElemOfXslElemIterate = false;
+ if (getParentElem() instanceof ElemIterate) {
+ isChildElemOfXslElemIterate = true;
+ }
- if(!vars.isLocalSet(m_index)) {
- // The caller of this stylesheet callable component, didn't provide the
- // parameter value via xsl:with-param instruction.
-
- // We'll determine the parameter's value by evaluating either the parameter's
- // 'select' attribute, or the contained sequence constructor within xsl:param
- // element.
+ if (!vars.isLocalSet(m_index) || (isChildElemOfXslElemIterate && (xslIterateIterationIdx == 0))) {
+ // The caller of an stylesheet callable component (associated with this xsl:param element),
+ // didn't provide xsl:param's value via xsl:with-param instruction.
int sourceNode = transformer.getXPathContext().getCurrentNode();
try {
XObject var = getValue(transformer, sourceNode);
- if (var == null) {
+ if (var != null) {
+ transformer.getXPathContext().getVarStack().setLocalVariable(m_index, var);
+ }
+ else {
throw new TransformerException("XTTE0590 : The value to parameter " + m_qname.toString() + " cannot be assigned. "
+ "Either an input content for parameter is not available within "
- + "stylesheet context, or parameter's value cannot be cast to an expected type.", srcLocator);
+ + "stylesheet context, or parameter's value cannot be cast to an expected type.", srcLocator);
}
-
- transformer.getXPathContext().getVarStack().setLocalVariable(m_index, var);
}
catch (TransformerException ex) {
throw new TransformerException("XTTE0590 : The value to parameter " + m_qname.toString() + " cannot be assigned. "
@@ -146,12 +152,13 @@ public class ElemParam extends ElemVariable
}
}
else {
- // The caller of this stylesheet callable component, has provided the
- // parameter's value via xsl:with-param instruction.
+ // The caller of an stylesheet callable component (associated with this xsl:param element),
+ // has provided xsl:param's value via xsl:with-param instruction.
- // If the xsl:param instruction has 'as' attribute, we'll check below
- // whether the parameter's value conforms to the sequence type specified by
+ // If the xsl:param instruction has an 'as' attribute, we check below
+ // whether xsl:param's value conforms to the sequence type specified by
// xsl:param's 'as' attribute.
+ String asAttrVal = getAs();
if (asAttrVal != null) {
try {
@@ -172,9 +179,15 @@ public class ElemParam extends ElemVariable
}
}
+ // Reset this class field
+ xslIterateIterationIdx = -1;
if (transformer.getDebug())
transformer.getTraceManager().fireTraceEndEvent(this);
}
+ public void setXslIterateIterationIdx(int iterationIdx) {
+ xslIterateIterationIdx = iterationIdx;
+ }
+
}
diff --git a/src/org/apache/xalan/transformer/TransformerImpl.java b/src/org/apache/xalan/transformer/TransformerImpl.java
index 7c35fdd8..75e585a8 100644
--- a/src/org/apache/xalan/transformer/TransformerImpl.java
+++ b/src/org/apache/xalan/transformer/TransformerImpl.java
@@ -363,6 +363,16 @@ public class TransformerImpl extends Transformer
/** NEEDSDOC Field m_shouldReset */
private boolean m_shouldReset = true;
+
+ /**
+ * A class field, to support xsl:iterate instruction evaluation.
+ */
+ private boolean isXslIterateBreakEvaluated = false;
+
+ /**
+ * A class field, to support xsl:iterate instruction evaluation.
+ */
+ private boolean isXslIterateOnCompletionActive = false;
/**
* NEEDSDOC Method setShouldReset
@@ -3789,5 +3799,21 @@ public class TransformerImpl extends Transformer
return m_source_location;
}
+ public boolean isXslIterateBreakEvaluated() {
+ return isXslIterateBreakEvaluated;
+ }
+
+ public void setXslIterateBreakEvaluated(boolean isXslIterateBreakEvaluated) {
+ this.isXslIterateBreakEvaluated = isXslIterateBreakEvaluated;
+ }
+
+ public boolean isXslIterateOnCompletionActive() {
+ return isXslIterateOnCompletionActive;
+ }
+
+ public void setXslIterateOnCompletionActive(boolean isXslIterateOnCompletionActive) {
+ this.isXslIterateOnCompletionActive = isXslIterateOnCompletionActive;
+ }
+
} // end TransformerImpl class
diff --git a/src/org/apache/xalan/xslt/util/XslTransformSharedDatastore.java b/src/org/apache/xalan/xslt/util/XslTransformSharedDatastore.java
index c6c67fac..5ac34555 100644
--- a/src/org/apache/xalan/xslt/util/XslTransformSharedDatastore.java
+++ b/src/org/apache/xalan/xslt/util/XslTransformSharedDatastore.java
@@ -27,11 +27,5 @@ public class XslTransformSharedDatastore {
// XSLT document's uri, used for error reporting
public static String xslSystemId;
-
- // To support xsl:iterate instruction evaluation
- public static Boolean isXslIterateBreakEvaluated = Boolean.FALSE;
-
- // To support xsl:iterate instruction evaluation
- public static Boolean isXslIterateOnCompletionActive = Boolean.FALSE;
}
diff --git a/tests/org/apache/xalan/xslt3/XslIterateTests.java b/tests/org/apache/xalan/xslt3/XslIterateTests.java
index 761bba01..61faffdc 100644
--- a/tests/org/apache/xalan/xslt3/XslIterateTests.java
+++ b/tests/org/apache/xalan/xslt3/XslIterateTests.java
@@ -290,5 +290,45 @@ public class XslIterateTests extends XslTransformTestsUtil {
runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
}
+
+ @Test
+ public void xslIterateTest25() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test23.xsl";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test23.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test23.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslIterateTest26() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test24.xsl";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test24.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test24.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslIterateTest27() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test25.xsl";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test25.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test25.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslIterateTest28() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_g.xml";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test26.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test26.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
}
diff --git a/tests/xsl_iterate/gold/test23.out b/tests/xsl_iterate/gold/test23.out
new file mode 100644
index 00000000..439348bf
--- /dev/null
+++ b/tests/xsl_iterate/gold/test23.out
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <factorial num="5">120</factorial>
+ <factorial num="6">720</factorial>
+</result>
diff --git a/tests/xsl_iterate/gold/test24.out b/tests/xsl_iterate/gold/test24.out
new file mode 100644
index 00000000..bed9f2e2
--- /dev/null
+++ b/tests/xsl_iterate/gold/test24.out
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <factorial num="1">1</factorial>
+ <factorial num="2">2</factorial>
+ <factorial num="3">6</factorial>
+ <factorial num="4">24</factorial>
+ <factorial num="5">120</factorial>
+ <factorial num="6">720</factorial>
+ <factorial num="7">5040</factorial>
+</result>
diff --git a/tests/xsl_iterate/gold/test25.out b/tests/xsl_iterate/gold/test25.out
new file mode 100644
index 00000000..439348bf
--- /dev/null
+++ b/tests/xsl_iterate/gold/test25.out
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <factorial num="5">120</factorial>
+ <factorial num="6">720</factorial>
+</result>
diff --git a/tests/xsl_iterate/gold/test26.out b/tests/xsl_iterate/gold/test26.out
new file mode 100644
index 00000000..bed9f2e2
--- /dev/null
+++ b/tests/xsl_iterate/gold/test26.out
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <factorial num="1">1</factorial>
+ <factorial num="2">2</factorial>
+ <factorial num="3">6</factorial>
+ <factorial num="4">24</factorial>
+ <factorial num="5">120</factorial>
+ <factorial num="6">720</factorial>
+ <factorial num="7">5040</factorial>
+</result>
diff --git a/tests/xsl_iterate/test1_g.xml b/tests/xsl_iterate/test1_g.xml
new file mode 100644
index 00000000..7931220e
--- /dev/null
+++ b/tests/xsl_iterate/test1_g.xml
@@ -0,0 +1,4 @@
+<info>
+ <from>1</from>
+ <to>7</to>
+</info>
\ No newline at end of file
diff --git a/tests/xsl_iterate/test23.xsl b/tests/xsl_iterate/test23.xsl
new file mode 100644
index 00000000..33414d0a
--- /dev/null
+++ b/tests/xsl_iterate/test23.xsl
@@ -0,0 +1,64 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ exclude-result-prefixes="xs"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- An XSLT stylesheet test case, to test xsl:iterate instruction. -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <result>
+ <!-- Evaluate factorial of a positive integer value. -->
+ <xsl:variable name="inpNum" select="5" as="xs:integer"/>
+ <xsl:iterate select="2 to $inpNum">
+ <xsl:param name="result" select="1" as="xs:integer"/>
+ <xsl:on-completion>
+ <factorial num="{$inpNum}">
+ <xsl:value-of select="$result"/>
+ </factorial>
+ </xsl:on-completion>
+ <xsl:variable name="currVal" select="."/>
+ <xsl:next-iteration>
+ <xsl:with-param name="result" select="$result * $currVal" as="xs:integer"/>
+ </xsl:next-iteration>
+ </xsl:iterate>
+
+ <!-- Evaluate factorial of another positive integer value. -->
+ <xsl:variable name="inpNum" select="6" as="xs:integer"/>
+ <xsl:iterate select="2 to $inpNum">
+ <xsl:param name="result" select="1" as="xs:integer"/>
+ <xsl:on-completion>
+ <factorial num="{$inpNum}">
+ <xsl:value-of select="$result"/>
+ </factorial>
+ </xsl:on-completion>
+ <xsl:variable name="currVal" select="."/>
+ <xsl:next-iteration>
+ <xsl:with-param name="result" select="$result * $currVal" as="xs:integer"/>
+ </xsl:next-iteration>
+ </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>
\ No newline at end of file
diff --git a/tests/xsl_iterate/test24.xsl b/tests/xsl_iterate/test24.xsl
new file mode 100644
index 00000000..25a3f2f0
--- /dev/null
+++ b/tests/xsl_iterate/test24.xsl
@@ -0,0 +1,72 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:fn0="http://fn0"
+ exclude-result-prefixes="xs fn0"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- An XSLT stylesheet test case, to test xsl:iterate instruction. -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <result>
+ <!-- Evaluate factorial of various positive integer values,
+ provided by xsl:for-each instruction.
+ -->
+ <xsl:for-each select="1 to 7">
+ <xsl:variable name="num" select="." as="xs:integer"/>
+ <xsl:copy-of select="fn0:factorial($num)"/>
+ </xsl:for-each>
+ </result>
+ </xsl:template>
+
+ <!-- A stylesheet function, to evaluate factorial of a positive
+ integer value.
+ -->
+ <xsl:function name="fn0:factorial" as="element(factorial)">
+ <xsl:param name="inpNum" as="xs:integer"/>
+
+ <xsl:choose>
+ <xsl:when test="$inpNum = 1">
+ <factorial num="{$inpNum}">
+ <xsl:value-of select="1"/>
+ </factorial>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:iterate select="2 to $inpNum">
+ <xsl:param name="result" select="1" as="xs:integer"/>
+ <xsl:on-completion>
+ <factorial num="{$inpNum}">
+ <xsl:value-of select="$result"/>
+ </factorial>
+ </xsl:on-completion>
+ <xsl:variable name="currVal" select="."/>
+ <xsl:next-iteration>
+ <xsl:with-param name="result" select="$result * $currVal" as="xs:integer"/>
+ </xsl:next-iteration>
+ </xsl:iterate>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:function>
+
+ <!--
+ * 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>
\ No newline at end of file
diff --git a/tests/xsl_iterate/test25.xsl b/tests/xsl_iterate/test25.xsl
new file mode 100644
index 00000000..b29c3b9f
--- /dev/null
+++ b/tests/xsl_iterate/test25.xsl
@@ -0,0 +1,69 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ exclude-result-prefixes="xs"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- An XSLT stylesheet test case, to test xsl:iterate instruction. -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <result>
+ <!-- Evaluate factorial of a positive integer value, by invoking a
+ stylesheet named template.
+ -->
+ <xsl:variable name="inpNum" select="5" as="xs:integer"/>
+ <xsl:call-template name="factorial">
+ <xsl:with-param name="inpNum" select="$inpNum" as="xs:integer"/>
+ </xsl:call-template>
+
+ <!-- Evaluate factorial of another positive integer value, by invoking a
+ stylesheet named template.
+ -->
+ <xsl:variable name="inpNum" select="6" as="xs:integer"/>
+ <xsl:call-template name="factorial">
+ <xsl:with-param name="inpNum" select="$inpNum" as="xs:integer"/>
+ </xsl:call-template>
+ </result>
+ </xsl:template>
+
+ <!-- A stylesheet named template, to evaluate factorial of a positive
+ integer value.
+ -->
+ <xsl:template name="factorial" as="element(factorial)">
+ <xsl:param name="inpNum" as="xs:integer"/>
+ <xsl:iterate select="2 to $inpNum">
+ <xsl:param name="result" select="1" as="xs:integer"/>
+ <xsl:on-completion>
+ <factorial num="{$inpNum}">
+ <xsl:value-of select="$result"/>
+ </factorial>
+ </xsl:on-completion>
+ <xsl:variable name="currVal" select="."/>
+ <xsl:next-iteration>
+ <xsl:with-param name="result" select="$result * $currVal" as="xs:integer"/>
+ </xsl:next-iteration>
+ </xsl:iterate>
+ </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>
\ No newline at end of file
diff --git a/tests/xsl_iterate/test26.xsl b/tests/xsl_iterate/test26.xsl
new file mode 100644
index 00000000..ca721a8d
--- /dev/null
+++ b/tests/xsl_iterate/test26.xsl
@@ -0,0 +1,75 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ exclude-result-prefixes="xs"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- use with test1_g.xml -->
+
+ <!-- An XSLT stylesheet test case, to test xsl:iterate instruction. -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/info">
+ <result>
+ <!-- Evaluate factorial of various positive integer values,
+ provided by xsl:for-each instruction.
+ -->
+ <xsl:for-each select="xs:integer(from) to xs:integer(to)">
+ <xsl:variable name="inpNum" select="."/>
+ <xsl:call-template name="factorial">
+ <xsl:with-param name="inpNum" select="$inpNum" as="xs:integer"/>
+ </xsl:call-template>
+ </xsl:for-each>
+ </result>
+ </xsl:template>
+
+ <!-- A stylesheet named template, to evaluate factorial of a positive
+ integer value.
+ -->
+ <xsl:template name="factorial" as="element(factorial)">
+ <xsl:param name="inpNum" as="xs:integer"/>
+
+ <xsl:choose>
+ <xsl:when test="$inpNum = 1">
+ <factorial num="{$inpNum}">
+ <xsl:value-of select="1"/>
+ </factorial>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:iterate select="2 to $inpNum">
+ <xsl:param name="result" select="1" as="xs:integer"/>
+ <xsl:on-completion>
+ <factorial num="{$inpNum}">
+ <xsl:value-of select="$result"/>
+ </factorial>
+ </xsl:on-completion>
+ <xsl:variable name="currVal" select="."/>
+ <xsl:next-iteration>
+ <xsl:with-param name="result" select="$result * $currVal"/>
+ </xsl:next-iteration>
+ </xsl:iterate>
+ </xsl:otherwise>
+ </xsl:choose>
+ </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>
\ 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