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/15 14:43:06 UTC
[xalan-java] branch xalan-j_xslt3.0 updated: committing implementation of xslt 3.0 xsl:sequence instruction, along with few new related working 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 f344cee2 committing implementation of xslt 3.0 xsl:sequence instruction, along with few new related working test cases.
new a9199858 Merge pull request #85 from mukulga/xalan-j_xslt3.0_mukul
f344cee2 is described below
commit f344cee2040514a423f10f4e0ac3d7fe96f3e533
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Fri Sep 15 20:07:52 2023 +0530
committing implementation of xslt 3.0 xsl:sequence instruction, along with few new related working test cases.
---
src/org/apache/xalan/processor/XSLTSchema.java | 19 +-
src/org/apache/xalan/templates/Constants.java | 9 +-
.../apache/xalan/templates/ElemApplyTemplates.java | 2 +-
src/org/apache/xalan/templates/ElemCopyOf.java | 34 +-
src/org/apache/xalan/templates/ElemFunction.java | 174 +++++++-
src/org/apache/xalan/templates/ElemSequence.java | 483 +++++++++++++++++++++
src/org/apache/xalan/templates/ElemTemplate.java | 2 +-
src/org/apache/xalan/templates/ElemVariable.java | 48 +-
src/org/apache/xpath/compiler/XPathParser.java | 2 +-
tests/org/apache/xalan/xslt3/AllXsl3Tests.java | 2 +-
.../apache/xalan/xslt3/XslSequenceInstTests.java | 103 +++++
tests/xsl_sequence_inst/gold/test1.out | 1 +
tests/xsl_sequence_inst/gold/test2.out | 1 +
tests/xsl_sequence_inst/gold/test3.out | 1 +
tests/xsl_sequence_inst/gold/test4.out | 1 +
tests/xsl_sequence_inst/gold/test5.out | 6 +
tests/xsl_sequence_inst/test1.xsl | 45 ++
tests/xsl_sequence_inst/test1_a.xml | 22 +
tests/xsl_sequence_inst/test2.xsl | 55 +++
tests/xsl_sequence_inst/test3.xsl | 46 ++
tests/xsl_sequence_inst/test4.xsl | 42 ++
tests/xsl_sequence_inst/test5.xsl | 53 +++
22 files changed, 1101 insertions(+), 50 deletions(-)
diff --git a/src/org/apache/xalan/processor/XSLTSchema.java b/src/org/apache/xalan/processor/XSLTSchema.java
index 8e3a9816..afca93ab 100644
--- a/src/org/apache/xalan/processor/XSLTSchema.java
+++ b/src/org/apache/xalan/processor/XSLTSchema.java
@@ -54,6 +54,7 @@ import org.apache.xalan.templates.ElemNumber;
import org.apache.xalan.templates.ElemOtherwise;
import org.apache.xalan.templates.ElemPI;
import org.apache.xalan.templates.ElemParam;
+import org.apache.xalan.templates.ElemSequence;
import org.apache.xalan.templates.ElemSort;
import org.apache.xalan.templates.ElemTemplate;
import org.apache.xalan.templates.ElemText;
@@ -244,7 +245,7 @@ public class XSLTSchema extends XSLTElementDef
XSLTAttributeDef.T_EXPR, false, false, XSLTAttributeDef.ERROR);
// Optional.
- // xsl:variable, xsl:param, xsl:with-param, xsl:attribute, xsl:break, xsl:on-completion
+ // xsl:variable, xsl:param, xsl:with-param, xsl:attribute, xsl:break, xsl:on-completion, xsl:sequence
XSLTAttributeDef selectAttrOpt = new XSLTAttributeDef(null, "select",
XSLTAttributeDef.T_EXPR, false, false, XSLTAttributeDef.ERROR);
@@ -394,11 +395,11 @@ public class XSLTSchema extends XSLTElementDef
new XSLTAttributeDef(Constants.S_XSLNAMESPACEURL, "*",
XSLTAttributeDef.T_CDATA, false, false,XSLTAttributeDef.WARNING);
- XSLTElementDef[] templateElements = new XSLTElementDef[31];
- XSLTElementDef[] templateElementsAndParams = new XSLTElementDef[32];
- XSLTElementDef[] templateElementsAndSort = new XSLTElementDef[32];
+ XSLTElementDef[] templateElements = new XSLTElementDef[32];
+ XSLTElementDef[] templateElementsAndParams = new XSLTElementDef[33];
+ XSLTElementDef[] templateElementsAndSort = new XSLTElementDef[33];
//exslt
- XSLTElementDef[] exsltFunctionElements = new XSLTElementDef[32];
+ XSLTElementDef[] exsltFunctionElements = new XSLTElementDef[33];
XSLTElementDef[] charTemplateElements = new XSLTElementDef[16];
XSLTElementDef resultElement = new XSLTElementDef(this, null, "*",
@@ -605,6 +606,13 @@ public class XSLTSchema extends XSLTElementDef
selectAttrOpt, asAttrOpt },
new ProcessorTemplateElem(),
ElemVariable.class /* class object */, 20, true);
+ XSLTElementDef xslSequence = new XSLTElementDef(this,
+ Constants.S_XSLNAMESPACEURL, "sequence",
+ null /*alias */,
+ templateElements /* elements */, // %template;>
+ new XSLTAttributeDef[]{ selectAttrOpt },
+ new ProcessorTemplateElem(),
+ ElemSequence.class /* class object */, 20, true);
XSLTElementDef xslParam = new XSLTElementDef(this,
Constants.S_XSLNAMESPACEURL, "param",
null /*alias */,
@@ -714,6 +722,7 @@ public class XSLTSchema extends XSLTElementDef
templateElements[i++] = xslText;
templateElements[i++] = xslCopy;
templateElements[i++] = xslVariable;
+ templateElements[i++] = xslSequence;
templateElements[i++] = xslMessage;
templateElements[i++] = xslFallback;
diff --git a/src/org/apache/xalan/templates/Constants.java b/src/org/apache/xalan/templates/Constants.java
index eccca64a..95d273db 100644
--- a/src/org/apache/xalan/templates/Constants.java
+++ b/src/org/apache/xalan/templates/Constants.java
@@ -104,9 +104,11 @@ public class Constants extends org.apache.xml.utils.Constants
ELEMNAME_ITERATE_BREAK = 97,
- ELEMNAME_FUNCTION = 98;
+ ELEMNAME_FUNCTION = 98,
- // next available number : 99
+ ELEMNAME_SEQUENCE = 99;
+
+ // next available number : 100
/**
* Literals for XSL element names. Note that there are more
@@ -188,7 +190,8 @@ public class Constants extends org.apache.xml.utils.Constants
ELEMNAME_VARIABLE_STRING = "variable",
ELEMNAME_WHEN_STRING = "when",
ELEMNAME_WITHPARAM_STRING = "with-param",
- ELEMNAME_FUNCTION_STRING = "function";
+ ELEMNAME_FUNCTION_STRING = "function",
+ ELEMNAME_SEQUENCE_STRING = "sequence";
/**
* Literals for EXSLT function elements.
diff --git a/src/org/apache/xalan/templates/ElemApplyTemplates.java b/src/org/apache/xalan/templates/ElemApplyTemplates.java
index 884c8536..18335495 100644
--- a/src/org/apache/xalan/templates/ElemApplyTemplates.java
+++ b/src/org/apache/xalan/templates/ElemApplyTemplates.java
@@ -420,7 +420,7 @@ public class ElemApplyTemplates extends ElemCallTemplate
}
else {
ElemCopyOf.copyOfActionOnResultSequence((ResultSequence)templateEvalResultForAsAttr,
- transformer, handler, xctxt);
+ transformer, handler, xctxt, false);
}
}
catch (TransformerException ex) {
diff --git a/src/org/apache/xalan/templates/ElemCopyOf.java b/src/org/apache/xalan/templates/ElemCopyOf.java
index 7deb8502..e2de4b8d 100644
--- a/src/org/apache/xalan/templates/ElemCopyOf.java
+++ b/src/org/apache/xalan/templates/ElemCopyOf.java
@@ -73,7 +73,7 @@ public class ElemCopyOf extends ElemTemplateElement
private Vector fVars;
private int fGlobalsSize;
- private final static char SPACE_CHAR = ' ';
+ public final static char SPACE_CHAR = ' ';
/**
* Set the "select" attribute.
@@ -197,7 +197,7 @@ public class ElemCopyOf extends ElemTemplateElement
break;
case XObject.CLASS_RESULT_SEQUENCE :
ResultSequence resultSequence = (ResultSequence)value;
- copyOfActionOnResultSequence(resultSequence, transformer, handler, xctxt);
+ copyOfActionOnResultSequence(resultSequence, transformer, handler, xctxt, false);
break;
default :
// no op
@@ -293,8 +293,8 @@ public class ElemCopyOf extends ElemTemplateElement
* Method to perform xsl:copy-of instruction's action, on an ResultSequence object.
*/
public static void copyOfActionOnResultSequence(ResultSequence resultSequence, TransformerImpl transformer,
- SerializationHandler serializationHandler,
- XPathContext xctxt) throws TransformerException, SAXException {
+ SerializationHandler serializationHandler,
+ XPathContext xctxt, boolean xslSeqProc) throws TransformerException, SAXException {
char[] spaceCharArr = new char[1];
spaceCharArr[0] = SPACE_CHAR;
@@ -305,23 +305,35 @@ public class ElemCopyOf extends ElemTemplateElement
if ((xdmItem instanceof XBoolean) || (xdmItem instanceof XNumber) || (xdmItem instanceof XString)) {
strVal = xdmItem.str();
- serializationHandler.characters(strVal.toCharArray(), 0, strVal.length());
- if (idx < (resultSequence.size() - 1)) {
- serializationHandler.characters(spaceCharArr, 0, 1);
+ if (xslSeqProc) {
+ strVal = strVal + ElemSequence.STRING_VAL_SERIALIZATION_SUFFIX;
+ serializationHandler.characters(strVal.toCharArray(), 0, strVal.length());
+ }
+ else {
+ serializationHandler.characters(strVal.toCharArray(), 0, strVal.length());
+ if (idx < (resultSequence.size() - 1)) {
+ serializationHandler.characters(spaceCharArr, 0, 1);
+ }
}
}
else if (xdmItem instanceof XSAnyAtomicType) {
strVal = ((XSAnyAtomicType)xdmItem).stringValue();
- serializationHandler.characters(strVal.toCharArray(), 0, strVal.length());
- if (idx < (resultSequence.size() - 1)) {
- serializationHandler.characters(spaceCharArr, 0, 1);
+ if (xslSeqProc) {
+ strVal = strVal + ElemSequence.STRING_VAL_SERIALIZATION_SUFFIX;
+ serializationHandler.characters(strVal.toCharArray(), 0, strVal.length());
+ }
+ else {
+ serializationHandler.characters(strVal.toCharArray(), 0, strVal.length());
+ if (idx < (resultSequence.size() - 1)) {
+ serializationHandler.characters(spaceCharArr, 0, 1);
+ }
}
}
else if (xdmItem.getType() == XObject.CLASS_NODESET) {
copyOfActionOnNodeSet((XNodeSet)xdmItem, transformer, serializationHandler, xctxt);
}
else if (xdmItem.getType() == XObject.CLASS_RESULT_SEQUENCE) {
- copyOfActionOnResultSequence((ResultSequence)xdmItem, transformer, serializationHandler, xctxt);
+ copyOfActionOnResultSequence((ResultSequence)xdmItem, transformer, serializationHandler, xctxt, xslSeqProc);
}
}
}
diff --git a/src/org/apache/xalan/templates/ElemFunction.java b/src/org/apache/xalan/templates/ElemFunction.java
index 8b297702..21834aa3 100644
--- a/src/org/apache/xalan/templates/ElemFunction.java
+++ b/src/org/apache/xalan/templates/ElemFunction.java
@@ -22,16 +22,34 @@ import javax.xml.transform.TransformerException;
import org.apache.xalan.transformer.TransformerImpl;
import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
+import org.apache.xml.dtm.ref.DTMNodeList;
import org.apache.xml.utils.QName;
import org.apache.xpath.VariableStack;
+import org.apache.xpath.XPath;
import org.apache.xpath.XPathContext;
+import org.apache.xpath.composite.SequenceTypeData;
import org.apache.xpath.composite.SequenceTypeSupport;
import org.apache.xpath.objects.ResultSequence;
import org.apache.xpath.objects.XNodeSet;
import org.apache.xpath.objects.XNodeSetForDOM;
import org.apache.xpath.objects.XObject;
import org.apache.xpath.objects.XRTreeFrag;
+import org.apache.xpath.xs.types.XSBoolean;
+import org.apache.xpath.xs.types.XSDate;
+import org.apache.xpath.xs.types.XSDateTime;
+import org.apache.xpath.xs.types.XSDayTimeDuration;
+import org.apache.xpath.xs.types.XSDecimal;
+import org.apache.xpath.xs.types.XSDouble;
+import org.apache.xpath.xs.types.XSDuration;
+import org.apache.xpath.xs.types.XSFloat;
+import org.apache.xpath.xs.types.XSInt;
+import org.apache.xpath.xs.types.XSInteger;
+import org.apache.xpath.xs.types.XSLong;
+import org.apache.xpath.xs.types.XSString;
+import org.apache.xpath.xs.types.XSYearMonthDuration;
+import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
/**
* Implementation of XSLT xsl:function element.
@@ -127,7 +145,7 @@ public class ElemFunction extends ElemTemplate
int paramCount = 0;
for (ElemTemplateElement elem = getFirstChildElem(); elem != null;
elem = elem.getNextSiblingElem()) {
- if(elem.getXSLToken() == Constants.ELEMNAME_PARAMVARIABLE) {
+ if (elem.getXSLToken() == Constants.ELEMNAME_PARAMVARIABLE) {
if (argSequence.size() < (paramCount + 1)) {
throw new TransformerException("XPST0017 : Cannot find a " + argSequence.size() + " argument function named "
+ "{" + funcNameSpaceUri + "}" + funcLocalName + "() within a stylesheet scope. "
@@ -175,24 +193,29 @@ public class ElemFunction extends ElemTemplate
NodeList nodeList = (new XRTreeFrag(df, xctxt, this)).convertToNodeset();
result = new XNodeSetForDOM(nodeList, xctxt);
-
+
XObject funcResultConvertedVal = result;
String funcAsAttrStrVal = getAs();
- if (funcAsAttrStrVal != null) {
+ if (funcAsAttrStrVal != null) {
try {
- funcResultConvertedVal = SequenceTypeSupport.convertXDMValueToAnotherType(result, funcAsAttrStrVal, null, xctxt);
+ funcResultConvertedVal = preprocessXslFunctionOrAVariableResult((XNodeSetForDOM)result, funcAsAttrStrVal, xctxt);
+
if (funcResultConvertedVal == null) {
- throw new TransformerException("XPTY0004 : The function call result for function {" + funcNameSpaceUri + "}" + funcLocalName +
- "(), doesn't match the declared function result type " +
- funcAsAttrStrVal + ".", srcLocator);
+ funcResultConvertedVal = SequenceTypeSupport.convertXDMValueToAnotherType(result, funcAsAttrStrVal, null, xctxt);
+
+ if (funcResultConvertedVal == null) {
+ throw new TransformerException("XPTY0004 : The function call result for function {" + funcNameSpaceUri + "}" + funcLocalName +
+ "(), doesn't match the declared function result type " +
+ funcAsAttrStrVal + ".", srcLocator);
+ }
}
}
catch (TransformerException ex) {
throw new TransformerException("XPTY0004 : The function call result for function {" + funcNameSpaceUri + "}" + funcLocalName +
"(), doesn't match the declared function result type " +
- funcAsAttrStrVal + ".", srcLocator);
+ funcAsAttrStrVal + ".", srcLocator);
}
}
@@ -251,5 +274,140 @@ public class ElemFunction extends ElemTemplate
{
root.recomposeTemplates(this);
}
+
+ /**
+ * This method helps us solve, XSLT's xsl:function and xsl:variable instruction use cases,
+ * where the XSL child contents of xsl:function or xsl:variable instructions contain
+ * xsl:sequence instruction(s).
+ *
+ * Given an initial result of computation of, XSL child contents of a xsl:function or xsl:variable
+ * instructions, and the function's or variable's expected data type, cast an input data
+ * value to the supplied expected data type.
+ */
+ public static ResultSequence preprocessXslFunctionOrAVariableResult(XNodeSetForDOM xNodeSetForDOM,
+ String sequenceTypeXPathExprStr,
+ XPathContext xctxt) throws TransformerException {
+ ResultSequence resultSequence = null;
+
+ DTMNodeList dtmNodeList = (DTMNodeList)(xNodeSetForDOM.object());
+
+ final int contextNode = xctxt.getContextNode();
+ SourceLocator srcLocator = xctxt.getSAXLocator();
+
+ XPath seqTypeXPath = new XPath(sequenceTypeXPathExprStr, srcLocator,
+ xctxt.getNamespaceContext(), XPath.SELECT, null, true);
+
+ XObject seqTypeExpressionEvalResult = seqTypeXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext());
+
+ SequenceTypeData seqExpectedTypeData = (SequenceTypeData)seqTypeExpressionEvalResult;
+
+ Node localRootNode = dtmNodeList.item(0);
+ NodeList nodeList = localRootNode.getChildNodes();
+ int nodeSetLen = nodeList.getLength();
+
+ if (nodeSetLen == 1) {
+ Node node = nodeList.item(0);
+ short nodeType = node.getNodeType();
+ if (nodeType == Node.TEXT_NODE) {
+ String strVal = ((Text)node).getNodeValue();
+ if (seqExpectedTypeData.getSequenceTypeKindTest() == null) {
+ resultSequence = new ResultSequence();
+ if ((seqExpectedTypeData.getItemTypeOccurrenceIndicator() == 0) ||
+ (seqExpectedTypeData.getItemTypeOccurrenceIndicator() ==
+ SequenceTypeSupport.OccurenceIndicator.ZERO_OR_ONE)) {
+ if (strVal.contains(ElemSequence.STRING_VAL_SERIALIZATION_SUFFIX)) {
+ strVal = strVal.replaceAll(ElemSequence.STRING_VAL_SERIALIZATION_SUFFIX, "");
+ XObject xObject = getXSTypedAtomicValue(strVal, seqExpectedTypeData.getSequenceType());
+ if (xObject != null) {
+ resultSequence.add(xObject);
+ }
+ }
+ else {
+ XObject xObject = getXSTypedAtomicValue(strVal, seqExpectedTypeData.getSequenceType());
+ if (xObject != null) {
+ resultSequence.add(xObject);
+ }
+ }
+ }
+ else {
+ if (strVal.contains(ElemSequence.STRING_VAL_SERIALIZATION_SUFFIX)) {
+ String[] strParts = strVal.split(ElemSequence.STRING_VAL_SERIALIZATION_SUFFIX);
+ for (int idx = 0; idx < strParts.length; idx++) {
+ String seqItemStrVal = strParts[idx];
+ XObject xObject = getXSTypedAtomicValue(seqItemStrVal, seqExpectedTypeData.getSequenceType());
+ if (xObject != null) {
+ resultSequence.add(xObject);
+ }
+ }
+ }
+ else {
+ XObject xObject = getXSTypedAtomicValue(strVal, seqExpectedTypeData.getSequenceType());
+ if (xObject != null) {
+ resultSequence.add(xObject);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return resultSequence;
+ }
+
+ /**
+ * Given XalanJ's integer code value of, an XML Schema built-in data type and a
+ * string representation of a data value, construct XalanJ's typed data object
+ * corresponding to the data type's integer code value.
+ */
+ private static XObject getXSTypedAtomicValue(String strVal, int sequenceType) throws TransformerException {
+
+ XObject result = null;
+
+ if (sequenceType == SequenceTypeSupport.BOOLEAN) {
+ boolean boolVal = ("false".equals(strVal) || "0".equals(strVal)) ? false : true;
+ result = new XSBoolean(boolVal);
+ }
+ else if (sequenceType == SequenceTypeSupport.STRING) {
+ result = new XSString(strVal);
+ }
+ else if (sequenceType == SequenceTypeSupport.XS_DATE) {
+ result = XSDate.parseDate(strVal);
+ }
+ else if (sequenceType == SequenceTypeSupport.XS_DATETIME) {
+ result = XSDateTime.parseDateTime(strVal);
+ }
+ else if (sequenceType == SequenceTypeSupport.XS_TIME) {
+ // TO DO
+ }
+ else if (sequenceType == SequenceTypeSupport.XS_DURATION) {
+ result = XSDuration.parseDuration(strVal);
+ }
+ else if (sequenceType == SequenceTypeSupport.XS_DAYTIME_DURATION) {
+ result = XSDayTimeDuration.parseDayTimeDuration(strVal);
+ }
+ else if (sequenceType == SequenceTypeSupport.XS_YEARMONTH_DURATION) {
+ result = XSYearMonthDuration.parseYearMonthDuration(strVal);
+ }
+ else if (sequenceType == SequenceTypeSupport.XS_DECIMAL) {
+ result = new XSDecimal(strVal);
+ }
+ else if (sequenceType == SequenceTypeSupport.XS_INTEGER) {
+ result = new XSInteger(strVal);
+ }
+ else if (sequenceType == SequenceTypeSupport.XS_LONG) {
+ result = new XSLong(strVal);
+ }
+ else if (sequenceType == SequenceTypeSupport.XS_INT) {
+ result = new XSInt(strVal);
+ }
+ else if (sequenceType == SequenceTypeSupport.XS_DOUBLE) {
+ result = new XSDouble(strVal);
+ }
+ else if (sequenceType == SequenceTypeSupport.XS_FLOAT) {
+ result = new XSFloat(strVal);
+ }
+
+ return result;
+ }
}
diff --git a/src/org/apache/xalan/templates/ElemSequence.java b/src/org/apache/xalan/templates/ElemSequence.java
new file mode 100644
index 00000000..3a60d150
--- /dev/null
+++ b/src/org/apache/xalan/templates/ElemSequence.java
@@ -0,0 +1,483 @@
+/*
+ * 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 java.util.List;
+import java.util.Vector;
+
+import javax.xml.transform.SourceLocator;
+import javax.xml.transform.TransformerException;
+
+import org.apache.xalan.serialize.SerializerUtils;
+import org.apache.xalan.transformer.TransformerImpl;
+import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xml.serializer.SerializationHandler;
+import org.apache.xpath.Expression;
+import org.apache.xpath.XPath;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.axes.LocPathIterator;
+import org.apache.xpath.axes.SelfIteratorNoPredicate;
+import org.apache.xpath.compiler.XPathParser;
+import org.apache.xpath.composite.SequenceTypeData;
+import org.apache.xpath.functions.FuncExtFunction;
+import org.apache.xpath.functions.Function;
+import org.apache.xpath.objects.InlineFunction;
+import org.apache.xpath.objects.ResultSequence;
+import org.apache.xpath.objects.XBoolean;
+import org.apache.xpath.objects.XNodeSet;
+import org.apache.xpath.objects.XNodeSetForDOM;
+import org.apache.xpath.objects.XNumber;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.objects.XRTreeFrag;
+import org.apache.xpath.objects.XString;
+import org.apache.xpath.operations.Operation;
+import org.apache.xpath.operations.Range;
+import org.apache.xpath.operations.SimpleMapOperator;
+import org.apache.xpath.xs.types.XSAnyAtomicType;
+import org.apache.xpath.xs.types.XSNumericType;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import com.sun.org.apache.xml.internal.dtm.DTM;
+
+/**
+ * Implementation of XSLT xsl:sequence element.
+ *
+ * Ref : https://www.w3.org/TR/xslt-30/#element-sequence
+ *
+ * @author Mukul Gandhi <mu...@apache.org>
+ *
+ * @xsl.usage advanced
+ */
+public class ElemSequence extends ElemTemplateElement
+{
+
+ private static final long serialVersionUID = 4299774714317634314L;
+
+ /**
+ * Constructor ElemSequence
+ */
+ public ElemSequence(){}
+
+ // The following two fields of this class, are used during
+ // XPath.fixupVariables(..) action as performed within object of
+ // this class.
+ private Vector fVars;
+ private int fGlobalsSize;
+
+ /**
+ * The value of the "select" attribute.
+ */
+ private XPath m_selectPattern;
+
+ /**
+ * We use this string value constant to add as a suffix to, a string value that
+ * is getting serialized by XalanJ serializer, when XSL serialization is
+ * getting done during evaluation of xsl:sequence instruction. This helps us
+ * construct later during XSL transformation process, a sequence of XDM atomic
+ * values.
+ *
+ * We're assuming that, this string value is significantly random, and is unlikely
+ * to exist within an input document that is getting transformed by XalanJ.
+ */
+ public static String STRING_VAL_SERIALIZATION_SUFFIX = "XSL_SEQ" + ElemCopyOf.SPACE_CHAR + "XSL_SEQ";
+
+ /**
+ * Set the value of "select" attribute.
+ *
+ * @param v Value to set for the "select" attribute.
+ */
+ public void setSelect(XPath v) {
+ m_selectPattern = v;
+ }
+
+ /**
+ * Get the value of "select" attribute.
+ *
+ * @return Value of the "select" attribute.
+ */
+ public XPath getSelect() {
+ return m_selectPattern;
+ }
+
+ /**
+ * Get an integer representation of the element type.
+ *
+ * @return An integer representation of the element, defined in the
+ * Constants class.
+ */
+ public int getXSLToken() {
+ return Constants.ELEMNAME_SEQUENCE;
+ }
+
+ /**
+ * Return the node name.
+ *
+ * @return The node name
+ */
+ public String getNodeName() {
+ return Constants.ELEMNAME_SEQUENCE_STRING;
+ }
+
+ /**
+ * @param transformer non-null reference to the the current transform-time state.
+ *
+ * @throws TransformerException
+ */
+ public void execute(TransformerImpl transformer) throws TransformerException {
+
+ int sourceNode = transformer.getXPathContext().getCurrentNode();
+
+ processXslSequence(transformer, sourceNode);
+ }
+
+ /**
+ * This method, helps to evaluate an xsl:sequence instruction.
+ *
+ * @param transformer non-null reference to the the current transform-time state.
+ * @param sourceNode non-null reference to the current source node.
+ *
+ * @throws TransformerException
+ */
+ public void processXslSequence(TransformerImpl transformer, int sourceNode)
+ throws TransformerException
+ {
+
+ XObject xslSequenceVal = null;
+
+ final XPathContext xctxtOriginal = transformer.getXPathContext();
+
+ XPathContext xctxt = transformer.getXPathContext();
+
+ xctxt.pushCurrentNode(sourceNode);
+
+ SourceLocator srcLocator = xctxt.getSAXLocator();
+
+ Expression selectExpression = null;
+
+ try {
+ if (m_selectPattern != null) {
+ selectExpression = m_selectPattern.getExpression();
+
+ if (selectExpression instanceof FuncExtFunction) {
+ XObject evalResult = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(xctxt,
+ selectExpression, transformer);
+ if (evalResult != null) {
+ xslSequenceVal = evalResult;
+ }
+ else {
+ xslSequenceVal = m_selectPattern.execute(xctxt, sourceNode, this);
+ }
+ }
+ else if ((selectExpression instanceof Function) ||
+ (selectExpression instanceof SimpleMapOperator) ||
+ (selectExpression instanceof Range)) {
+ xslSequenceVal = selectExpression.execute(xctxt);
+ }
+ else if (selectExpression instanceof Operation) {
+ Operation opn = (Operation)selectExpression;
+ XObject leftOperand = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(
+ xctxt, opn.getLeftOperand(), transformer);
+ XObject rightOperand = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(
+ xctxt, opn.getRightOperand(), transformer);
+ xslSequenceVal = opn.operate(leftOperand, rightOperand);
+ }
+ else if (selectExpression instanceof SelfIteratorNoPredicate) {
+ xslSequenceVal = xctxt.getXPath3ContextItem();
+ }
+ else if (selectExpression instanceof LocPathIterator) {
+ int contextNode = xctxt.getContextNode();
+
+ LocPathIterator locPathIterator = (LocPathIterator)selectExpression;
+
+ DTMIterator dtmIter = null;
+ try {
+ dtmIter = locPathIterator.asIterator(xctxt, contextNode);
+ }
+ catch (ClassCastException ex) {
+ // no op
+ }
+
+ if (dtmIter != null) {
+ xslSequenceVal = new XNodeSet(dtmIter);
+ }
+ else {
+ ResultSequence resultSeq = new ResultSequence();
+
+ String xpathExprStr = m_selectPattern.getPatternString();
+
+ if (xpathExprStr.startsWith("$") && xpathExprStr.contains("[") &&
+ xpathExprStr.endsWith("]")) {
+ ElemTemplateElement elemTemplateElement = (ElemTemplateElement)xctxt.getNamespaceContext();
+ List<XMLNSDecl> prefixTable = null;
+ if (elemTemplateElement != null) {
+ prefixTable = (List<XMLNSDecl>)elemTemplateElement.getPrefixTable();
+ }
+
+ String varRefXPathExprStr = "$" + xpathExprStr.substring(1, xpathExprStr.indexOf('['));
+ String xpathIndexExprStr = xpathExprStr.substring(xpathExprStr.indexOf('[') + 1,
+ xpathExprStr.indexOf(']'));
+
+ // Evaluate the, variable reference XPath expression
+ if (prefixTable != null) {
+ varRefXPathExprStr = XslTransformEvaluationHelper.replaceNsUrisWithPrefixesOnXPathStr(
+ varRefXPathExprStr,
+ prefixTable);
+ }
+
+ XPath varXPathObj = new XPath(varRefXPathExprStr, srcLocator, xctxt.getNamespaceContext(),
+ XPath.SELECT, null);
+ if (fVars != null) {
+ varXPathObj.fixupVariables(fVars, fGlobalsSize);
+ }
+
+ XObject varEvalResult = varXPathObj.execute(xctxt, xctxt.getCurrentNode(), xctxt.getNamespaceContext());
+
+ // Evaluate the, xdm sequence index XPath expression
+ if (prefixTable != null) {
+ xpathIndexExprStr = XslTransformEvaluationHelper.replaceNsUrisWithPrefixesOnXPathStr(
+ xpathIndexExprStr,
+ prefixTable);
+ }
+
+ XPath xpathIndexObj = new XPath(xpathIndexExprStr, srcLocator, xctxt.getNamespaceContext(),
+ XPath.SELECT, null);
+
+ if (fVars != null) {
+ xpathIndexObj.fixupVariables(fVars, fGlobalsSize);
+ }
+
+ XObject seqIndexEvalResult = xpathIndexObj.execute(xctxt, xctxt.getCurrentNode(),
+ xctxt.getNamespaceContext());
+
+ if (varEvalResult instanceof ResultSequence) {
+ ResultSequence varEvalResultSeq = (ResultSequence)varEvalResult;
+
+ if (seqIndexEvalResult instanceof XNumber) {
+ double dValIndex = ((XNumber)seqIndexEvalResult).num();
+ if (dValIndex == (int)dValIndex) {
+ XObject evalResult = varEvalResultSeq.item((int)dValIndex - 1);
+ resultSeq.add(evalResult);
+ }
+ else {
+ throw new javax.xml.transform.TransformerException("XPTY0004 : an index value used with an xdm "
+ + "sequence reference, is not an integer.", srcLocator);
+ }
+ }
+ else if (seqIndexEvalResult instanceof XSNumericType) {
+ String indexStrVal = ((XSNumericType)seqIndexEvalResult).stringValue();
+ double dValIndex = (Double.valueOf(indexStrVal)).doubleValue();
+ if (dValIndex == (int)dValIndex) {
+ XObject evalResult = varEvalResultSeq.item((int)dValIndex - 1);
+ resultSeq.add(evalResult);
+ }
+ else {
+ throw new javax.xml.transform.TransformerException("XPTY0004 : an index value used with an xdm "
+ + "sequence reference, is not an integer.", srcLocator);
+ }
+ }
+ else {
+ throw new javax.xml.transform.TransformerException("XPTY0004 : an index value used with an xdm sequence "
+ + "reference, is not numeric.", srcLocator);
+ }
+ }
+ }
+
+ xslSequenceVal = resultSeq;
+ }
+ }
+
+ if (xslSequenceVal == null) {
+ xslSequenceVal = m_selectPattern.execute(xctxt, sourceNode, this);
+ }
+ }
+ else if (getFirstChildElem() == null) {
+ xslSequenceVal = XString.EMPTYSTRING;
+ }
+ else {
+ int sequenceConstructDtmHandle = transformer.transformToRTF(this);
+ NodeList nodeList = (new XRTreeFrag(sequenceConstructDtmHandle, xctxt, this)).convertToNodeset();
+ xslSequenceVal = new XNodeSetForDOM(nodeList, xctxt);
+ }
+
+ if (xslSequenceVal == null) {
+ // The result of evaluation of xsl:sequence instruction here,
+ // is an empty sequence.
+ XPath emptySeqXPath = new XPath(XPathParser.XPATH_EXPR_STR_EMPTY_SEQUENCE, srcLocator,
+ null, XPath.SELECT, null);
+ xslSequenceVal = emptySeqXPath.execute(xctxt, DTM.NULL, null);
+ }
+
+ SerializationHandler handler = transformer.getSerializationHandler();
+
+ if (xslSequenceVal != null) {
+ int xObjectType = xslSequenceVal.getType();
+ String strVal = null;
+
+ switch (xObjectType) {
+ case XObject.CLASS_NODESET :
+ ElemCopyOf.copyOfActionOnNodeSet((XNodeSet)xslSequenceVal, transformer, handler, xctxt);
+ break;
+ case XObject.CLASS_RTREEFRAG :
+ SerializerUtils.outputResultTreeFragment(handler, xslSequenceVal, xctxt);
+ break;
+ case XObject.CLASS_RESULT_SEQUENCE :
+ ResultSequence resultSequence = (ResultSequence)xslSequenceVal;
+ ElemCopyOf.copyOfActionOnResultSequence(resultSequence, transformer, handler, xctxt, true);
+ break;
+ default :
+ // no op
+ }
+
+ boolean isToAddStrValSerializationSuffix = isToAddStrValSerializationSuffix(xctxt);
+
+ if ((xslSequenceVal instanceof XBoolean) || (xslSequenceVal instanceof XNumber) ||
+ (xslSequenceVal instanceof XString)) {
+ if (isToAddStrValSerializationSuffix) {
+ strVal = xslSequenceVal.str() + STRING_VAL_SERIALIZATION_SUFFIX;
+ }
+ else {
+ strVal = xslSequenceVal.str();
+ }
+
+ handler.characters(strVal.toCharArray(), 0, strVal.length());
+ }
+ else if (xslSequenceVal instanceof XSAnyAtomicType) {
+ if (isToAddStrValSerializationSuffix) {
+ strVal = ((XSAnyAtomicType)xslSequenceVal).stringValue() + STRING_VAL_SERIALIZATION_SUFFIX;
+ }
+ else {
+ strVal = ((XSAnyAtomicType)xslSequenceVal).stringValue();
+ }
+
+ handler.characters(strVal.toCharArray(), 0, strVal.length());
+ }
+ else if (xslSequenceVal instanceof InlineFunction) {
+ throw new TransformerException("XTDE0450 : Cannot add a function item to an XDM result tree, "
+ + "via xsl:sequence instruction.", srcLocator);
+ }
+ }
+ }
+ catch (SAXException se) {
+ throw new TransformerException(se);
+ }
+ finally {
+ xctxt.popCurrentNode();
+ }
+
+ // Restore the original xpath context, on the xslt transformer object
+ transformer.setXPathContext(xctxtOriginal);
+ }
+
+ /**
+ * This function is called after everything else has been
+ * recomposed, and allows the template to set remaining
+ * values that may be based on some other property that
+ * depends on recomposition.
+ */
+ public void compose(StylesheetRoot sroot) throws TransformerException {
+ StylesheetRoot.ComposeState cstate = sroot.getComposeState();
+
+ java.util.Vector vnames = cstate.getVariableNames();
+
+ fVars = (Vector)vnames.clone();
+ fGlobalsSize = cstate.getGlobalsSize();
+
+ if (m_selectPattern != null) {
+ m_selectPattern.fixupVariables(vnames, cstate.getGlobalsSize());
+ }
+
+ super.compose(sroot);
+ }
+
+ /**
+ * This after the template's children have been composed.
+ */
+ public void endCompose(StylesheetRoot sroot) throws TransformerException
+ {
+ super.endCompose(sroot);
+ }
+
+ /**
+ * Set the parent as an ElemTemplateElement.
+ *
+ * @param p This node's parent as an ElemTemplateElement
+ */
+ public void setParentElem(ElemTemplateElement p)
+ {
+ super.setParentElem(p);
+ }
+
+
+ /**
+ * Call the children visitors.
+ *
+ * @param visitor The visitor whose appropriate method will be called.
+ */
+ protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
+ {
+ if (m_selectPattern != null) {
+ m_selectPattern.getExpression().callVisitors(m_selectPattern, visitor);
+ }
+
+ super.callChildVisitors(visitor, callAttrs);
+ }
+
+ /**
+ * This method determines that, should a XalanJ serialization suffix be added, when
+ * emitting xdm atomic values to an XSLT result sequence.
+ */
+ private boolean isToAddStrValSerializationSuffix(XPathContext xctxt) throws TransformerException {
+
+ boolean isToAddStrValSerializationSuffix = true;
+
+ ElemTemplateElement elemTemplateElem = getParentElem();
+
+ String asAttrStrVal = null;
+
+ while (elemTemplateElem != null) {
+ if (elemTemplateElem instanceof ElemFunction) {
+ asAttrStrVal = ((ElemFunction)elemTemplateElem).getAs();
+ break;
+ }
+ else if (elemTemplateElem instanceof ElemVariable) {
+ asAttrStrVal = ((ElemVariable)elemTemplateElem).getAs();
+ break;
+ }
+ else {
+ elemTemplateElem = elemTemplateElem.getParentElem();
+ }
+ }
+
+ if (asAttrStrVal != null) {
+ XPath seqTypeXPath = new XPath(asAttrStrVal, xctxt.getSAXLocator(),
+ xctxt.getNamespaceContext(),
+ XPath.SELECT, null, true);
+ XObject seqTypeExpressionEvalResult = seqTypeXPath.execute(xctxt, xctxt.getContextNode(),
+ xctxt.getNamespaceContext());
+ SequenceTypeData seqExpectedTypeData = (SequenceTypeData)seqTypeExpressionEvalResult;
+ if (seqExpectedTypeData.getSequenceTypeKindTest() != null) {
+ isToAddStrValSerializationSuffix = false;
+ }
+ }
+
+ return isToAddStrValSerializationSuffix;
+ }
+
+}
diff --git a/src/org/apache/xalan/templates/ElemTemplate.java b/src/org/apache/xalan/templates/ElemTemplate.java
index 31c63ccb..3b996461 100644
--- a/src/org/apache/xalan/templates/ElemTemplate.java
+++ b/src/org/apache/xalan/templates/ElemTemplate.java
@@ -447,7 +447,7 @@ public class ElemTemplate extends ElemTemplateElement
}
else {
ElemCopyOf.copyOfActionOnResultSequence((ResultSequence)templateEvalResultForAsAttr,
- transformer, handler, xctxt);
+ transformer, handler, xctxt, false);
}
}
catch (TransformerException ex) {
diff --git a/src/org/apache/xalan/templates/ElemVariable.java b/src/org/apache/xalan/templates/ElemVariable.java
index 8ebf0c31..715ea666 100644
--- a/src/org/apache/xalan/templates/ElemVariable.java
+++ b/src/org/apache/xalan/templates/ElemVariable.java
@@ -315,7 +315,7 @@ public class ElemVariable extends ElemTemplateElement
* @throws TransformerException
*/
public XObject getValue(TransformerImpl transformer, int sourceNode)
- throws TransformerException
+ throws TransformerException
{
XObject var = null;
@@ -533,37 +533,47 @@ public class ElemVariable extends ElemTemplateElement
var = XString.EMPTYSTRING;
}
else {
- int df;
-
- try {
- if(m_parentNode instanceof Stylesheet) // Global variable
- df = transformer.transformToGlobalRTF(this);
- else
- df = transformer.transformToRTF(this);
- }
- finally {
- // no op
+ int rootNodeHandleOfRtf;
+
+ if (m_parentNode instanceof Stylesheet) {
+ // Global variable
+ rootNodeHandleOfRtf = transformer.transformToGlobalRTF(this);
}
+ else {
+ rootNodeHandleOfRtf = transformer.transformToRTF(this);
+ }
- // With XSLT 3.0, RTFs are treated as proper node sets
- NodeList nodeList = (new XRTreeFrag(df, xctxt, this)).convertToNodeset();
+ // With XSLT 3.0, RTFs are treated as XDM node sets
+ NodeList nodeList = (new XRTreeFrag(rootNodeHandleOfRtf, xctxt, this)).convertToNodeset();
- var = new XNodeSetForDOM(nodeList, xctxt);
+ var = new XNodeSetForDOM(nodeList, xctxt);
}
}
catch (SAXException se) {
- throw new TransformerException(se);
+ throw new TransformerException(se);
}
finally {
xctxt.popCurrentNode();
}
- // Restore the original xpath context, on the xslt transformer object
- transformer.setXPathContext(xctxtOriginal);
-
if (m_asAttr != null) {
- var = SequenceTypeSupport.convertXDMValueToAnotherType(var, m_asAttr, null, xctxt);
+ if (var instanceof XNodeSetForDOM) {
+ XObject variableConvertedVal = ElemFunction.preprocessXslFunctionOrAVariableResult(
+ (XNodeSetForDOM)var, m_asAttr, xctxt);
+ if (variableConvertedVal != null) {
+ var = variableConvertedVal;
+ }
+ else {
+ var = SequenceTypeSupport.convertXDMValueToAnotherType(var, m_asAttr, null, xctxt);
+ }
+ }
+ else {
+ var = SequenceTypeSupport.convertXDMValueToAnotherType(var, m_asAttr, null, xctxt);
+ }
}
+
+ // Restore the original xpath context, on the xslt transformer object
+ transformer.setXPathContext(xctxtOriginal);
return var;
diff --git a/src/org/apache/xpath/compiler/XPathParser.java b/src/org/apache/xpath/compiler/XPathParser.java
index f5eee541..070bcf49 100644
--- a/src/org/apache/xpath/compiler/XPathParser.java
+++ b/src/org/apache/xpath/compiler/XPathParser.java
@@ -109,7 +109,7 @@ public class XPathParser
// we translate that within this XPath parser implementation, to an XPath
// range "to" expression using this class field (this equivalently produces
// an xdm empty sequence).
- private static final String XPATH_EXPR_STR_EMPTY_SEQUENCE = "1 to 0";
+ public static final String XPATH_EXPR_STR_EMPTY_SEQUENCE = "1 to 0";
private static final List<String> fXpathOpArrTokensList = Arrays.asList(XPATH_OP_ARR);
diff --git a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
index 0742c207..e636536c 100644
--- a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
+++ b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
@@ -95,7 +95,7 @@ import org.junit.runners.Suite.SuiteClasses;
SequenceFunctionTests.class, FnParseXmlTests.class, FnParseXmlFragmentTests.class,
TemplateTests.class, FnAvgTests.class, FnMaxTests.class, FnMinTests.class, FnContainsTokenTests.class,
XslVariableAttributeAsTests.class, InstanceOfExprTests.class, XslTemplateAttributeAsTests.class,
- XslFunctionTests.class, FnRoundTests.class })
+ XslFunctionTests.class, FnRoundTests.class, XslSequenceInstTests.class })
public class AllXsl3Tests {
}
diff --git a/tests/org/apache/xalan/xslt3/XslSequenceInstTests.java b/tests/org/apache/xalan/xslt3/XslSequenceInstTests.java
new file mode 100644
index 00000000..9b255a0f
--- /dev/null
+++ b/tests/org/apache/xalan/xslt3/XslSequenceInstTests.java
@@ -0,0 +1,103 @@
+/*
+ * 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.xslt3;
+
+import org.apache.xalan.util.XslTransformTestsUtil;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * XSLT stylesheet test cases, to test xsl:sequence
+ * instruction.
+ *
+ * @author Mukul Gandhi <mu...@apache.org>
+ *
+ * @xsl.usage advanced
+ */
+public class XslSequenceInstTests extends XslTransformTestsUtil {
+
+ private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX +
+ "xsl_sequence_inst/";
+
+ private static final String XSL_TRANSFORM_GOLD_DIRPATH = XSLConstants.XSL_TRANSFORM_GOLD_DIRPATH_PREFIX +
+ "xsl_sequence_inst/gold/";
+
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ // no op
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ xmlDocumentBuilderFactory = null;
+ xmlDocumentBuilder = null;
+ xslTransformerFactory = null;
+ }
+
+ @Test
+ public void xslSequenceTest1() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1.xsl";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test1.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslSequenceTest2() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test2.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test2.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslSequenceTest3() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test3.xsl";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test3.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test3.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslSequenceTest4() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test4.xsl";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test4.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test4.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslSequenceTest5() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test5.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test5.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+}
diff --git a/tests/xsl_sequence_inst/gold/test1.out b/tests/xsl_sequence_inst/gold/test1.out
new file mode 100644
index 00000000..5f65a8a3
--- /dev/null
+++ b/tests/xsl_sequence_inst/gold/test1.out
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><output>37</output>
diff --git a/tests/xsl_sequence_inst/gold/test2.out b/tests/xsl_sequence_inst/gold/test2.out
new file mode 100644
index 00000000..2dd567c4
--- /dev/null
+++ b/tests/xsl_sequence_inst/gold/test2.out
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><output>4.36</output>
diff --git a/tests/xsl_sequence_inst/gold/test3.out b/tests/xsl_sequence_inst/gold/test3.out
new file mode 100644
index 00000000..6b1ef787
--- /dev/null
+++ b/tests/xsl_sequence_inst/gold/test3.out
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><output>10</output>
diff --git a/tests/xsl_sequence_inst/gold/test4.out b/tests/xsl_sequence_inst/gold/test4.out
new file mode 100644
index 00000000..9cde98ba
--- /dev/null
+++ b/tests/xsl_sequence_inst/gold/test4.out
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><output>2010-10-05</output>
diff --git a/tests/xsl_sequence_inst/gold/test5.out b/tests/xsl_sequence_inst/gold/test5.out
new file mode 100644
index 00000000..1041290d
--- /dev/null
+++ b/tests/xsl_sequence_inst/gold/test5.out
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?><output>
+ <productsSummary>
+ <count>5</count>
+ <avgPrice>4.04</avgPrice>
+ </productsSummary>
+</output>
diff --git a/tests/xsl_sequence_inst/test1.xsl b/tests/xsl_sequence_inst/test1.xsl
new file mode 100644
index 00000000..2821af63
--- /dev/null
+++ b/tests/xsl_sequence_inst/test1.xsl
@@ -0,0 +1,45 @@
+<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, to test an xsl:sequence
+ instruction.
+
+ This stylesheet example, is borrowed from XSLT 3.0
+ spec.
+ -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <output>
+ <xsl:variable name="values" as="xs:integer*">
+ <xsl:sequence select="(1,2,3,4)"/>
+ <xsl:sequence select="(8,9,10)"/>
+ </xsl:variable>
+ <xsl:value-of select="sum($values)"/>
+ </output>
+ </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_sequence_inst/test1_a.xml b/tests/xsl_sequence_inst/test1_a.xml
new file mode 100644
index 00000000..518fcd98
--- /dev/null
+++ b/tests/xsl_sequence_inst/test1_a.xml
@@ -0,0 +1,22 @@
+<products>
+ <product price="5">
+ <id>1</id>
+ <desc>a1</desc>
+ </product>
+ <product cost="3.2">
+ <id>2</id>
+ <desc>a2</desc>
+ </product>
+ <product price="2">
+ <id>3</id>
+ <desc>a3</desc>
+ </product>
+ <product price="7">
+ <id>4</id>
+ <desc>a4</desc>
+ </product>
+ <product price="3">
+ <id>5</id>
+ <desc>a5</desc>
+ </product>
+</products>
\ No newline at end of file
diff --git a/tests/xsl_sequence_inst/test2.xsl b/tests/xsl_sequence_inst/test2.xsl
new file mode 100644
index 00000000..9baf9efb
--- /dev/null
+++ b/tests/xsl_sequence_inst/test2.xsl
@@ -0,0 +1,55 @@
+<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_a.xml -->
+
+ <!-- An XSLT stylesheet test, to test an xsl:sequence
+ instruction.
+
+ This stylesheet example, is borrowed from XSLT 3.0
+ spec.
+ -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <output>
+ <xsl:variable name="prices" as="xs:decimal*">
+ <xsl:for-each select="//product">
+ <xsl:choose>
+ <xsl:when test="@price">
+ <xsl:sequence select="xs:decimal(@price)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:sequence select="xs:decimal(@cost) * 1.5"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:value-of select="avg($prices)"/>
+ </output>
+ </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_sequence_inst/test3.xsl b/tests/xsl_sequence_inst/test3.xsl
new file mode 100644
index 00000000..5ae2d88b
--- /dev/null
+++ b/tests/xsl_sequence_inst/test3.xsl
@@ -0,0 +1,46 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:fn0="http://ns0"
+ exclude-result-prefixes="xs fn0"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- An XSLT stylesheet test, to test an xsl:sequence
+ instruction.
+ -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <output>
+ <xsl:value-of select="count(fn0:func1())"/>
+ </output>
+ </xsl:template>
+
+ <xsl:function name="fn0:func1" as="xs:integer*">
+ <xsl:for-each select="1 to 10">
+ <xsl:variable name="val" select="."/>
+ <xsl:sequence select="$val"/>
+ </xsl:for-each>
+ </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_sequence_inst/test4.xsl b/tests/xsl_sequence_inst/test4.xsl
new file mode 100644
index 00000000..529c6b05
--- /dev/null
+++ b/tests/xsl_sequence_inst/test4.xsl
@@ -0,0 +1,42 @@
+<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, to test an xsl:sequence
+ instruction.
+ -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <output>
+ <xsl:variable name="dates" as="xs:date*">
+ <xsl:sequence select="(xs:date('2005-10-12'), xs:date('2001-10-02'),
+ xs:date('2010-10-05'), xs:date('2003-10-07'))"/>
+ </xsl:variable>
+ <xsl:value-of select="max($dates)"/>
+ </output>
+ </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_sequence_inst/test5.xsl b/tests/xsl_sequence_inst/test5.xsl
new file mode 100644
index 00000000..e17d3fbe
--- /dev/null
+++ b/tests/xsl_sequence_inst/test5.xsl
@@ -0,0 +1,53 @@
+<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 -->
+
+ <!-- use with test1_a.xml -->
+
+ <!-- An XSLT stylesheet test, to test an xsl:sequence
+ instruction.
+ -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/products">
+ <output>
+ <xsl:copy-of select="fn0:analyzeProductList(product)"/>
+ </output>
+ </xsl:template>
+
+ <xsl:function name="fn0:analyzeProductList" as="element()">
+ <xsl:param name="productList" as="element()*"/>
+ <productsSummary>
+ <count>
+ <xsl:sequence select="count($productList)"/>
+ </count>
+ <avgPrice>
+ <xsl:sequence select="avg(for $product in $productList return ($product/@price | $product/@cost))"/>
+ </avgPrice>
+ </productsSummary>
+ </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
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xalan.apache.org
For additional commands, e-mail: commits-help@xalan.apache.org