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 2024/06/04 11:11:03 UTC
(xalan-java) branch xalan-j_xslt3.0 updated: committing implementation of xpath3.1 arrow operator(=>), along with few 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 0a7d5184 committing implementation of xpath3.1 arrow operator(=>), along with few working related test cases
0a7d5184 is described below
commit 0a7d5184591f0e774b12e9533052b0973d99f8c6
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Tue Jun 4 16:40:49 2024 +0530
committing implementation of xpath3.1 arrow operator(=>), along with few working related test cases
---
src/org/apache/xalan/templates/ElemVariable.java | 5 +-
src/org/apache/xpath/XPath.java | 39 ++++-
src/org/apache/xpath/compiler/Compiler.java | 45 ++++--
src/org/apache/xpath/compiler/Lexer.java | 10 +-
src/org/apache/xpath/compiler/OpCodes.java | 4 +-
src/org/apache/xpath/compiler/XPathParserImpl.java | 65 +++++---
src/org/apache/xpath/functions/Function.java | 18 ++-
src/org/apache/xpath/functions/FunctionOneArg.java | 7 +-
src/org/apache/xpath/operations/ArrowOp.java | 164 +++++++++++++++++++++
src/org/apache/xpath/operations/Operation.java | 88 ++++++-----
.../org/apache/xalan/xpath3/XPathArrowOpTests.java | 80 ++++++++++
tests/org/apache/xalan/xslt3/Xsl3TestSuite1.java | 4 +-
tests/xpath_arrow_op/gold/test1.out | 9 ++
tests/xpath_arrow_op/gold/test2.out | 1 +
tests/xpath_arrow_op/gold/test3.out | 4 +
tests/xpath_arrow_op/test1.xsl | 50 +++++++
tests/xpath_arrow_op/test2.xsl | 35 +++++
tests/xpath_arrow_op/test3.xsl | 41 ++++++
18 files changed, 575 insertions(+), 94 deletions(-)
diff --git a/src/org/apache/xalan/templates/ElemVariable.java b/src/org/apache/xalan/templates/ElemVariable.java
index f8dce265..b35f0302 100644
--- a/src/org/apache/xalan/templates/ElemVariable.java
+++ b/src/org/apache/xalan/templates/ElemVariable.java
@@ -49,6 +49,7 @@ import org.apache.xpath.objects.XPathMap;
import org.apache.xpath.objects.XRTreeFrag;
import org.apache.xpath.objects.XRTreeFragSelectWrapper;
import org.apache.xpath.objects.XString;
+import org.apache.xpath.operations.ArrowOp;
import org.apache.xpath.operations.Operation;
import org.apache.xpath.operations.Range;
import org.apache.xpath.operations.SimpleMapOperator;
@@ -404,8 +405,8 @@ public class ElemVariable extends ElemTemplateElement
return evalResult;
}
- else if (selectExpression instanceof Range) {
- XObject evalResult = ((Range)selectExpression).execute(xctxt);
+ else if ((selectExpression instanceof Range) || (selectExpression instanceof ArrowOp)) {
+ XObject evalResult = selectExpression.execute(xctxt);
if (m_asAttr != null) {
evalResult = SequenceTypeSupport.convertXdmValueToAnotherType(evalResult, m_asAttr, null, xctxt);
diff --git a/src/org/apache/xpath/XPath.java b/src/org/apache/xpath/XPath.java
index 297ab2cb..b54067e9 100644
--- a/src/org/apache/xpath/XPath.java
+++ b/src/org/apache/xpath/XPath.java
@@ -44,6 +44,7 @@ import org.apache.xpath.functions.Function;
import org.apache.xpath.objects.ResultSequence;
import org.apache.xpath.objects.XNumber;
import org.apache.xpath.objects.XObject;
+import org.apache.xpath.operations.ArrowOp;
import org.apache.xpath.res.XPATHErrorResources;
import xml.xpath31.processor.types.XSNumericType;
@@ -71,6 +72,12 @@ public class XPath implements Serializable, ExpressionOwner
// this class.
private Vector fVars;
private int fGlobalsSize;
+
+ /**
+ * This class field, is used when evaluating an
+ * XPath arrow operator, "=>".
+ */
+ private String fArrowOpRemainingXPathExprStr = null;
/**
* initial the function table
@@ -179,17 +186,22 @@ public class XPath implements Serializable, ExpressionOwner
m_patternString = exprString;
XPathParserImpl parser = new XPathParserImpl(errorListener, locator);
- Compiler compiler = new Compiler(errorListener, locator, m_funcTable);
-
- if (SELECT == type)
+ Compiler compiler = new Compiler(errorListener, locator, m_funcTable);
+
+ if (SELECT == type) {
parser.initXPath(compiler, exprString, prefixResolver, false);
+ fArrowOpRemainingXPathExprStr = parser.getArrowOpRemainingXPathExprStr();
+ }
else if (MATCH == type)
parser.initMatchPattern(compiler, exprString, prefixResolver);
else
throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_CANNOT_DEAL_XPATH_TYPE, new Object[]{Integer.toString(type)})); //"Can not deal with XPath type: " + type);
Expression expr = compiler.compile(0);
-
+ if (expr instanceof ArrowOp) {
+ ((ArrowOp)expr).setArrowOpRemainingXPathExprStr(fArrowOpRemainingXPathExprStr);
+ }
+
this.setExpression(expr);
if((null != locator) && locator instanceof ExpressionNode)
@@ -226,10 +238,12 @@ public class XPath implements Serializable, ExpressionOwner
m_patternString = exprString;
XPathParserImpl parser = new XPathParserImpl(errorListener, locator);
- Compiler compiler = new Compiler(errorListener, locator, m_funcTable);
-
- if (SELECT == type)
+ Compiler compiler = new Compiler(errorListener, locator, m_funcTable);
+
+ if (SELECT == type) {
parser.initXPath(compiler, exprString, prefixResolver, false);
+ fArrowOpRemainingXPathExprStr = parser.getArrowOpRemainingXPathExprStr();
+ }
else if (MATCH == type)
parser.initMatchPattern(compiler, exprString, prefixResolver);
else
@@ -238,6 +252,9 @@ public class XPath implements Serializable, ExpressionOwner
new Object[]{Integer.toString(type)}));
Expression expr = compiler.compile(0);
+ if (expr instanceof ArrowOp) {
+ ((ArrowOp)expr).setArrowOpRemainingXPathExprStr(fArrowOpRemainingXPathExprStr);
+ }
this.setExpression(expr);
@@ -776,4 +793,12 @@ public class XPath implements Serializable, ExpressionOwner
*/
public static final double MATCH_SCORE_OTHER = 0.5;
+ public String getArrowOpRemainingXPathExprStr() {
+ return fArrowOpRemainingXPathExprStr;
+ }
+
+ public void setArrowOpRemainingXPathExprStr(String arrowOpRemainingXPathExprStr) {
+ this.fArrowOpRemainingXPathExprStr = arrowOpRemainingXPathExprStr;
+ }
+
}
diff --git a/src/org/apache/xpath/compiler/Compiler.java b/src/org/apache/xpath/compiler/Compiler.java
index 0f28468f..eb0ee2f8 100644
--- a/src/org/apache/xpath/compiler/Compiler.java
+++ b/src/org/apache/xpath/compiler/Compiler.java
@@ -41,6 +41,7 @@ import org.apache.xpath.functions.WrongNumberArgsException;
import org.apache.xpath.objects.XNumber;
import org.apache.xpath.objects.XString;
import org.apache.xpath.operations.And;
+import org.apache.xpath.operations.ArrowOp;
import org.apache.xpath.operations.CastAs;
import org.apache.xpath.operations.CastableAs;
import org.apache.xpath.operations.Div;
@@ -201,6 +202,10 @@ public class Compiler extends OpMap
expr = range(opPos); break;
case OpCodes.OP_STR_CONCAT :
expr = strConcat(opPos); break;
+ case OpCodes.OP_ARROW :
+ fIsCompileFuncPrecededByCompileArrow = true;
+ expr = arrowOp(opPos);
+ break;
case OpCodes.OP_MINUS :
expr = minus(opPos); break;
case OpCodes.OP_MULT :
@@ -257,7 +262,7 @@ public class Compiler extends OpMap
}
// if(null != expr)
// expr.setSourceLocator(m_locator);
-
+
return expr;
}
@@ -653,6 +658,18 @@ public class Compiler extends OpMap
{
return compileOperation(new StrConcat(), opPos);
}
+
+ /**
+ * Compile an XPath 3.1 arrow "=>" operation.
+ *
+ * @param opPos The current position in the m_opMap array.
+ *
+ * @throws TransformerException if a error occurs creating the Expression.
+ */
+ protected Expression arrowOp(int opPos) throws TransformerException
+ {
+ return compileOperation(new ArrowOp(), opPos);
+ }
/**
* Compile a '-' operation.
@@ -1334,13 +1351,18 @@ private static final boolean DEBUG = false;
int i = 0;
for (int p = opPos; p < endFunc; p = getNextOpPos(p), i++)
+ {
+ func.setArg(compile(p), i);
+ }
+
+ if (fIsCompileFuncPrecededByCompileArrow)
{
-
- // System.out.println("argPos: "+ p);
- // System.out.println("argCode: "+ m_opMap[p]);
- func.setArg(compile(p), i);
+ // This allows us to, permit the absence of XPath function's 1st
+ // argument when evaluating with operator "=>".
+ i++;
+ fIsCompileFuncPrecededByCompileArrow = false;
}
-
+
func.checkNumberArgs(i);
}
catch (WrongNumberArgsException wnae)
@@ -1348,9 +1370,8 @@ private static final boolean DEBUG = false;
java.lang.String name = m_functionTable.getFunctionName(funcID);
m_errorHandler.fatalError( new TransformerException(
- XSLMessages.createXPATHMessage(XPATHErrorResources.ER_ONLY_ALLOWS,
- new Object[]{name, wnae.getMessage()}), m_locator));
- //"name + " only allows " + wnae.getMessage() + " arguments", m_locator));
+ XSLMessages.createXPATHMessage(XPATHErrorResources.ER_ONLY_ALLOWS,
+ new Object[]{name, wnae.getMessage()}), m_locator));
}
return func;
@@ -1693,4 +1714,10 @@ private static final boolean DEBUG = false;
* The FunctionTable for all xpath build-in functions
*/
private FunctionTable m_functionTable;
+
+ /**
+ * We store within this class field, the fact that, there is
+ * an XPath expression of kind "... => functionCall()".
+ */
+ private boolean fIsCompileFuncPrecededByCompileArrow;
}
diff --git a/src/org/apache/xpath/compiler/Lexer.java b/src/org/apache/xpath/compiler/Lexer.java
index cd4e85c8..b93901f5 100644
--- a/src/org/apache/xpath/compiler/Lexer.java
+++ b/src/org/apache/xpath/compiler/Lexer.java
@@ -258,7 +258,7 @@ class Lexer
if ((pat.length() > (i + 1)) && (pat.charAt(i + 1) == '|')) {
// added for XPath 3.1.
// to recognize the character sequence "||", as an XPath
- // language token.
+ // token.
addToTokenQueue(pat.substring(i, i + 2));
i += 1;
break;
@@ -267,6 +267,14 @@ class Lexer
case '*' :
case '+' :
case '=' :
+ if ((pat.length() > (i + 1)) && (pat.charAt(i + 1) == '>')) {
+ // added for XPath 3.1.
+ // to recognize the character sequence "=>", as an XPath
+ // token.
+ addToTokenQueue(pat.substring(i, i + 2));
+ i += 1;
+ break;
+ }
case ',' :
case '\\' : // Unused at the moment
case '^' : // Unused at the moment
diff --git a/src/org/apache/xpath/compiler/OpCodes.java b/src/org/apache/xpath/compiler/OpCodes.java
index 9105c9dc..159350fe 100644
--- a/src/org/apache/xpath/compiler/OpCodes.java
+++ b/src/org/apache/xpath/compiler/OpCodes.java
@@ -736,8 +736,10 @@ public class OpCodes
public static final int OP_CAST_AS = 77;
public static final int OP_CASTABLE_AS = 78;
+
+ public static final int OP_ARROW = 79;
/** The next free ID. Please keep this up to date. */
- private static final int NEXT_FREE_ID = 79;
+ private static final int NEXT_FREE_ID = 80;
}
diff --git a/src/org/apache/xpath/compiler/XPathParserImpl.java b/src/org/apache/xpath/compiler/XPathParserImpl.java
index 38960213..5e1e26e3 100644
--- a/src/org/apache/xpath/compiler/XPathParserImpl.java
+++ b/src/org/apache/xpath/compiler/XPathParserImpl.java
@@ -47,8 +47,8 @@ import org.apache.xpath.composite.SequenceTypeFunctionTest;
import org.apache.xpath.composite.SequenceTypeKindTest;
import org.apache.xpath.composite.SequenceTypeMapTest;
import org.apache.xpath.composite.SequenceTypeSupport;
-import org.apache.xpath.composite.XPathSequenceConstructor;
import org.apache.xpath.composite.XPathArrayConstructor;
+import org.apache.xpath.composite.XPathSequenceConstructor;
import org.apache.xpath.composite.XPathSequenceTypeExpr;
import org.apache.xpath.domapi.XPathStylesheetDOM3Exception;
import org.apache.xpath.functions.DynamicFunctionCall;
@@ -119,8 +119,8 @@ public class XPathParserImpl
"eq", "ne", "lt", "gt", "le", "ge",
"for", "in", "return", "if", "then",
"else", "some", "every", "satisfies",
- "let", ":=", "-", "||", "instance", "of",
- "as" };
+ "let", ":=", "-", "||", "=>", "instance",
+ "of", "as" };
// If an XPath expression is () (i.e, representing an xdm empty sequence),
// we translate that within this XPath parser implementation, to an XPath
@@ -158,6 +158,8 @@ public class XPathParserImpl
static XPathSequenceTypeExpr fXpathSequenceTypeExpr = null;
+ private String fArrowOpRemainingXPathExprStr = null;
+
/**
* The parser constructor.
*/
@@ -2095,7 +2097,7 @@ public class XPathParserImpl
}
else
{
- // Support for XPath 3.1 language simple map operator '!'.
+ // Support for XPath 3.1 simple map operator '!'.
// An XPath expression SEQ!Expr evaluates an expression Expr once for every
// item in the sequence obtained by evaluating SEQ. An XPath language operator "!"
@@ -2130,7 +2132,7 @@ public class XPathParserImpl
}
else if (tokenIs("eq"))
{
- // Support for XPath 3.1 language value comparison operator "eq"
+ // Support for XPath 3.1 value comparison operator "eq"
nextToken();
insertOp(addPos, 2, OpCodes.OP_VC_EQUALS);
@@ -2144,7 +2146,7 @@ public class XPathParserImpl
}
else if (tokenIs("ne"))
{
- // Support for XPath 3.1 language value comparison operator "ne"
+ // Support for XPath 3.1 value comparison operator "ne"
nextToken();
insertOp(addPos, 2, OpCodes.OP_VC_NOT_EQUALS);
@@ -2211,7 +2213,7 @@ public class XPathParserImpl
}
else if (tokenIs('<'))
{
- // Support for XPath 3.1 language node comparison operator "<<"
+ // Support for XPath 3.1 node comparison operator "<<"
nextToken();
insertOp(addPos, 2, OpCodes.OP_NC_PRECEDE);
@@ -2239,7 +2241,7 @@ public class XPathParserImpl
}
else if (tokenIs('>'))
{
- // Support for XPath 3.1 language node comparison operator ">>"
+ // Support for XPath 3.1 node comparison operator ">>"
nextToken();
insertOp(addPos, 2, OpCodes.OP_NC_FOLLOWS);
@@ -2258,7 +2260,7 @@ public class XPathParserImpl
}
else if (tokenIs("to"))
{
- // Support for XPath 3.1 language range expressions.
+ // Support for XPath 3.1 range expression (i.e, an XPath operator "to").
// An XPath language range expressions are used to construct a
// sequence of consecutive integers. For e.g, an XPath language range expression
@@ -2279,7 +2281,7 @@ public class XPathParserImpl
}
else if (tokenIs("||"))
{
- // Support for XPath 3.1 language string concatenation operator "||".
+ // Support for XPath 3.1 string concatenation operator "||".
// An XPath language string concatenation operator "||" may be used as an
// alternative means, for XPath string concatenation function 'concat'.
@@ -2295,9 +2297,28 @@ public class XPathParserImpl
m_ops.getOp(addPos + op1 + 1) + op1);
addPos += 2;
}
+ else if (tokenIs("=>"))
+ {
+ // Support for XPath 3.1 arrow operator "=>"
+
+ consumeExpected("=>");
+
+ insertOp(addPos, 2, OpCodes.OP_ARROW);
+
+ FunctionCall();
+
+ if (m_token != null) {
+ fArrowOpRemainingXPathExprStr = "";
+ }
+
+ while (m_token != null) {
+ fArrowOpRemainingXPathExprStr += m_token;
+ nextToken();
+ }
+ }
else if (tokenIs("lt"))
{
- // Support for XPath 3.1 language value comparison operator "lt"
+ // Support for XPath 3.1 value comparison operator "lt"
nextToken();
@@ -2312,7 +2333,7 @@ public class XPathParserImpl
}
else if (tokenIs("gt"))
{
- // Support for XPath 3.1 language value comparison operator "gt"
+ // Support for XPath 3.1 value comparison operator "gt"
nextToken();
@@ -2327,7 +2348,7 @@ public class XPathParserImpl
}
else if (tokenIs("le"))
{
- // Support for XPath 3.1 language value comparison operator "le"
+ // Support for XPath 3.1 value comparison operator "le"
nextToken();
@@ -2342,7 +2363,7 @@ public class XPathParserImpl
}
else if (tokenIs("ge"))
{
- // Support for XPath 3.1 language value comparison operator "ge"
+ // Support for XPath 3.1 value comparison operator "ge"
nextToken();
@@ -2357,7 +2378,7 @@ public class XPathParserImpl
}
else if (tokenIs("is"))
{
- // Support for XPath 3.1 language node comparison operator "is"
+ // Support for XPath 3.1 node comparison operator "is"
nextToken();
@@ -2371,7 +2392,7 @@ public class XPathParserImpl
addPos += 2;
}
else if (tokenIs("instance") && lookahead("of", 1)) {
- // Support for XPath 3.1 language "instance of" expression.
+ // Support for XPath 3.1 "instance of" expression.
// An XPath language, "instance of" operator requires two operands. An
// XPath evaluation for "instance of" expression returns value 'true',
@@ -2392,7 +2413,7 @@ public class XPathParserImpl
addPos += 2;
}
else if (tokenIs("cast") && lookahead("as", 1)) {
- // Support for XPath 3.1 language "cast as" expression.
+ // Support for XPath 3.1 "cast as" expression.
// An XPath expression "cast as" converts an input value,
// to another value of a specific datatype.
@@ -2413,7 +2434,7 @@ public class XPathParserImpl
addPos += 2;
}
else if (tokenIs("castable") && lookahead("as", 1)) {
- // Support for XPath 3.1 language "castable as" expression.
+ // Support for XPath 3.1 "castable as" expression.
// An XPath expression "castable as" tests (i.e, returns true, or false)
// whether a given value is castable into another datatype.
@@ -2870,7 +2891,7 @@ public class XPathParserImpl
matchFound = true;
}
else if ((m_tokenChar == '$') && (lookahead('(', 2))) {
- // Support for XPath 3.1 language dynamic function calls.
+ // Support for XPath 3.1 'dynamic function call' expression.
// For example, if an XPath inline function expression is bound
// to an XSLT variable as follows : <xsl:variable name="sqr" select="function($val) { $val * $val }"/>,
@@ -2975,7 +2996,7 @@ public class XPathParserImpl
matchFound = true;
}
else if (tokenIs("function") && lookahead('(', 1)) {
- // Support for XPath 3.1 language "inline function" expressions
+ // Support for XPath 3.1 "inline function" expression
// Ref : https://www.w3.org/TR/xpath-31/#id-inline-func
@@ -4803,4 +4824,8 @@ public class XPathParserImpl
}
}
+ public String getArrowOpRemainingXPathExprStr() {
+ return fArrowOpRemainingXPathExprStr;
+ }
+
}
diff --git a/src/org/apache/xpath/functions/Function.java b/src/org/apache/xpath/functions/Function.java
index 6e89ce37..7b157d08 100644
--- a/src/org/apache/xpath/functions/Function.java
+++ b/src/org/apache/xpath/functions/Function.java
@@ -40,9 +40,14 @@ import org.apache.xpath.objects.XObject;
*/
public abstract class Function extends Expression
{
- static final long serialVersionUID = 6927661240854599768L;
+ static final long serialVersionUID = 6927661240854599768L;
+
+ /**
+ * The first argument passed to the function (at index 0).
+ */
+ protected Expression m_arg0;
- /**
+ /**
* Set an argument expression for a function. This method is called by the
* XPath compiler.
*
@@ -141,4 +146,13 @@ public abstract class Function extends Expression
{
// no default action
}
+
+ public Expression getArg0()
+ {
+ return m_arg0;
+ }
+
+ public void setArg0(Expression arg0) {
+ m_arg0 = arg0;
+ }
}
diff --git a/src/org/apache/xpath/functions/FunctionOneArg.java b/src/org/apache/xpath/functions/FunctionOneArg.java
index dd9a9bab..124e9d87 100644
--- a/src/org/apache/xpath/functions/FunctionOneArg.java
+++ b/src/org/apache/xpath/functions/FunctionOneArg.java
@@ -31,12 +31,7 @@ import org.apache.xpath.XPathVisitor;
*/
public class FunctionOneArg extends Function implements ExpressionOwner
{
- static final long serialVersionUID = -5180174180765609758L;
-
- /** The first argument passed to the function (at index 0).
- *
- */
- Expression m_arg0;
+ static final long serialVersionUID = -5180174180765609758L;
private boolean fArgCountErr = false;
diff --git a/src/org/apache/xpath/operations/ArrowOp.java b/src/org/apache/xpath/operations/ArrowOp.java
new file mode 100644
index 00000000..a465fe26
--- /dev/null
+++ b/src/org/apache/xpath/operations/ArrowOp.java
@@ -0,0 +1,164 @@
+/*
+ * 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.xpath.operations;
+
+import javax.xml.transform.SourceLocator;
+import javax.xml.transform.TransformerException;
+
+import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
+import org.apache.xpath.Expression;
+import org.apache.xpath.XPath;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.functions.Function;
+import org.apache.xpath.functions.Function2Args;
+import org.apache.xpath.functions.Function3Args;
+import org.apache.xpath.functions.FunctionOneArg;
+import org.apache.xpath.functions.WrongNumberArgsException;
+import org.apache.xpath.objects.XObject;
+
+/**
+ * Implementation of XPath 3.1 arrow operator, "=>".
+ *
+ * Ref : https://www.w3.org/TR/xpath-31/#id-arrow-operator
+ *
+ * @author Mukul Gandhi <mu...@apache.org>
+ *
+ * @xsl.usage advanced
+ */
+public class ArrowOp extends Operation
+{
+
+ private static final long serialVersionUID = 4577709194385888770L;
+
+ private java.lang.String fArrowOpRemainingXPathExprStr;
+
+ /**
+ * Evaluate an XPath arrow operator, and return the result.
+ *
+ * @param left non-null reference to the evaluated left operand.
+ * @param right non-null reference to the evaluated right operand.
+ *
+ * @return non-null reference to the XObject that represents the result of the operation.
+ *
+ * @throws javax.xml.transform.TransformerException
+ */
+ public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException {
+
+ XObject result = null;
+
+ SourceLocator srcLocator = xctxt.getSAXLocator();
+
+ Function function = (Function)m_right;
+
+ if (function instanceof Function3Args) {
+ Function3Args funcThreeArgs = (Function3Args)function;
+ Expression arg0 = funcThreeArgs.getArg0();
+ Expression arg1 = funcThreeArgs.getArg1();
+ funcThreeArgs.setArg0(m_left);
+
+ try {
+ if (arg0 != null) {
+ funcThreeArgs.setArg(arg0, 1);
+ }
+ if (arg1 != null) {
+ funcThreeArgs.setArg(arg1, 2);
+ }
+ }
+ catch (WrongNumberArgsException ex) {
+ throw new javax.xml.transform.TransformerException("FORX0003 : An error occured, during evaluation for "
+ + "operator =>.", srcLocator);
+ }
+
+ result = funcThreeArgs.execute(xctxt);
+ }
+ else if (function instanceof Function2Args) {
+ Function2Args funcTwoArgs = (Function2Args)function;
+ Expression arg1 = funcTwoArgs.getArg1();
+
+ if (arg1 != null) {
+ throw new javax.xml.transform.TransformerException("FORX0003 : The function's 2nd argument cannot be provided "
+ + "lexically for an XPath function of arity 2 with evaluation using "
+ + "operator =>.", srcLocator);
+ }
+ else {
+ Expression arg0 = funcTwoArgs.getArg0();
+ funcTwoArgs.setArg0(m_left);
+ try {
+ funcTwoArgs.setArg(arg0, 1);
+ }
+ catch (WrongNumberArgsException ex) {
+ throw new javax.xml.transform.TransformerException("FORX0003 : An error occured, during evaluation for "
+ + "operator =>.", srcLocator);
+ }
+ result = funcTwoArgs.execute(xctxt);
+ }
+ }
+ else if (function instanceof FunctionOneArg) {
+ FunctionOneArg funcOneArg = (FunctionOneArg)function;
+ Expression arg0 = funcOneArg.getArg0();
+
+ if (arg0 != null) {
+ throw new javax.xml.transform.TransformerException("FORX0003 : The function's 1st argument cannot be provided lexically "
+ + "for an XPath function of arity 1 with evaluation using "
+ + "operator =>.", srcLocator);
+ }
+ else {
+ funcOneArg.setArg0(m_left);
+ result = funcOneArg.execute(xctxt);
+ }
+ }
+
+ if (fArrowOpRemainingXPathExprStr != null) {
+ result = getFinalResult(result, fArrowOpRemainingXPathExprStr, xctxt);
+ }
+
+ return result;
+ }
+
+ public java.lang.String getArrowOpRemainingXPathExprStr() {
+ return fArrowOpRemainingXPathExprStr;
+ }
+
+ public void setArrowOpRemainingXPathExprStr(java.lang.String arrowOpRemainingXPathExprStr) {
+ this.fArrowOpRemainingXPathExprStr = arrowOpRemainingXPathExprStr;
+ }
+
+ /**
+ * This method handles more than one '=>' operator occurrences, within an XPath expression.
+ */
+ private XObject getFinalResult(XObject prevResult, java.lang.String arrowOpRemainingXPathExprStr,
+ XPathContext xctxt) throws TransformerException {
+ XObject result = null;
+
+ SourceLocator srcLocator = xctxt.getSAXLocator();
+
+ java.lang.String resultStr = XslTransformEvaluationHelper.getStrVal(prevResult);
+ java.lang.String xpathStr = "'" + resultStr + "'" + arrowOpRemainingXPathExprStr;
+ XPath xpath = new XPath(xpathStr, srcLocator, xctxt.getNamespaceContext(), XPath.SELECT, null);
+ int contextNode = xctxt.getCurrentNode();
+ result = xpath.execute(xctxt, contextNode, xctxt.getNamespaceContext());
+
+ java.lang.String xpathStr2 = xpath.getArrowOpRemainingXPathExprStr();
+ if (xpathStr2 != null) {
+ result = getFinalResult(result, xpathStr2, xctxt);
+ }
+
+ return result;
+ }
+
+}
diff --git a/src/org/apache/xpath/operations/Operation.java b/src/org/apache/xpath/operations/Operation.java
index da2508be..426d4a92 100644
--- a/src/org/apache/xpath/operations/Operation.java
+++ b/src/org/apache/xpath/operations/Operation.java
@@ -118,51 +118,49 @@ public class Operation extends Expression implements ExpressionOwner
XObject right = null;
- if (m_left instanceof FuncExtFunction) {
- FuncExtFunction extFunction = (FuncExtFunction)m_left;
- if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(extFunction.getNamespace())) {
- left = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(
- xctxt, m_left, null);
- }
- else {
- left = m_left.execute(xctxt, true);
- }
- }
- else if (m_left instanceof SelfIteratorNoPredicate) {
- XObject xpath3ContextItem = xctxt.getXPath3ContextItem();
- if (xpath3ContextItem != null) {
- left = xpath3ContextItem;
- }
- else {
- left = m_left.execute(xctxt, true);
- }
- }
- else {
- left = m_left.execute(xctxt, true);
- }
-
- if (m_right instanceof FuncExtFunction) {
- FuncExtFunction extFunction = (FuncExtFunction)m_right;
- if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(extFunction.getNamespace())) {
- right = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(
- xctxt, m_right, null);
- }
- else {
- right = m_right.execute(xctxt, true);
- }
- }
- else if (m_right instanceof SelfIteratorNoPredicate) {
- XObject xpath3ContextItem = xctxt.getXPath3ContextItem();
- if (xpath3ContextItem != null) {
- right = xpath3ContextItem;
- }
- else {
- right = m_right.execute(xctxt, true);
- }
- }
- else {
- right = m_right.execute(xctxt, true);
- }
+ if (m_left instanceof FuncExtFunction) {
+ FuncExtFunction extFunction = (FuncExtFunction)m_left;
+ if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(extFunction.getNamespace())) {
+ left = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(xctxt, m_left, null);
+ }
+ else {
+ left = m_left.execute(xctxt, true);
+ }
+ }
+ else if (m_left instanceof SelfIteratorNoPredicate) {
+ XObject xpath3ContextItem = xctxt.getXPath3ContextItem();
+ if (xpath3ContextItem != null) {
+ left = xpath3ContextItem;
+ }
+ else {
+ left = m_left.execute(xctxt, true);
+ }
+ }
+ else {
+ left = m_left.execute(xctxt, true);
+ }
+
+ if (m_right instanceof FuncExtFunction) {
+ FuncExtFunction extFunction = (FuncExtFunction)m_right;
+ if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(extFunction.getNamespace())) {
+ right = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(xctxt, m_right, null);
+ }
+ else {
+ right = m_right.execute(xctxt, true);
+ }
+ }
+ else if (m_right instanceof SelfIteratorNoPredicate) {
+ XObject xpath3ContextItem = xctxt.getXPath3ContextItem();
+ if (xpath3ContextItem != null) {
+ right = xpath3ContextItem;
+ }
+ else {
+ right = m_right.execute(xctxt, true);
+ }
+ }
+ else {
+ right = m_right.execute(xctxt, true);
+ }
XObject result = operate(left, right);
diff --git a/tests/org/apache/xalan/xpath3/XPathArrowOpTests.java b/tests/org/apache/xalan/xpath3/XPathArrowOpTests.java
new file mode 100644
index 00000000..6012bd81
--- /dev/null
+++ b/tests/org/apache/xalan/xpath3/XPathArrowOpTests.java
@@ -0,0 +1,80 @@
+/*
+ * 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.xpath3;
+
+import org.apache.xalan.util.XSLConstants;
+import org.apache.xalan.util.XSLTransformTestsUtil;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * XPath 3.1 arrow operator "=>", test cases.
+ *
+ * @author Mukul Gandhi <mu...@apache.org>
+ *
+ * @xsl.usage advanced
+ */
+public class XPathArrowOpTests extends XSLTransformTestsUtil {
+
+ private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX + "xpath_arrow_op/";
+
+ private static final String XSL_TRANSFORM_GOLD_DIRPATH = XSLConstants.XSL_TRANSFORM_GOLD_DIRPATH_PREFIX + "xpath_arrow_op/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 xslXPathArrowOpTest1() {
+ 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 xslXPathArrowOpTest2() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test2.xsl";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test2.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test2.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslXPathArrowOpTest3() {
+ 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);
+ }
+
+}
diff --git a/tests/org/apache/xalan/xslt3/Xsl3TestSuite1.java b/tests/org/apache/xalan/xslt3/Xsl3TestSuite1.java
index 76130ea0..444f0e47 100644
--- a/tests/org/apache/xalan/xslt3/Xsl3TestSuite1.java
+++ b/tests/org/apache/xalan/xslt3/Xsl3TestSuite1.java
@@ -34,6 +34,7 @@ import org.apache.xalan.xpath3.InlineFunctionItemExprTests;
import org.apache.xalan.xpath3.StringTests;
import org.apache.xalan.xpath3.ValueComparisonTests;
import org.apache.xalan.xpath3.XPathArrayTests;
+import org.apache.xalan.xpath3.XPathArrowOpTests;
import org.apache.xalan.xpath3.XPathCastTests;
import org.apache.xalan.xpath3.XPathMapTests;
import org.apache.xalan.xpath3.XsConstructorFunctionTests;
@@ -64,7 +65,8 @@ import org.junit.runners.Suite.SuiteClasses;
XmlDotComHigherOrderFunctionsTests.class, FnDefaultCollation.class,
FnBaseUriTests.class, FnDocumentUriTests.class, FnResolveQNameTests.class,
FnQNameTests.class, XPathMapTests.class, XPathArrayTests.class, FnLangTests.class,
- FnRootTests.class, FnParseJsonTests.class, XPathCastTests.class })
+ FnRootTests.class, FnParseJsonTests.class, XPathCastTests.class,
+ XPathArrowOpTests.class })
public class Xsl3TestSuite1 {
}
diff --git a/tests/xpath_arrow_op/gold/test1.out b/tests/xpath_arrow_op/gold/test1.out
new file mode 100644
index 00000000..02701672
--- /dev/null
+++ b/tests/xpath_arrow_op/gold/test1.out
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <one>ABC</one>
+ <two>true</two>
+ <three>false</three>
+ <four>
+ <item>abc</item>
+ <item>pqr</item>
+ </four>
+</result>
diff --git a/tests/xpath_arrow_op/gold/test2.out b/tests/xpath_arrow_op/gold/test2.out
new file mode 100644
index 00000000..03d7c615
--- /dev/null
+++ b/tests/xpath_arrow_op/gold/test2.out
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><result>ABCDEFGHI</result>
diff --git a/tests/xpath_arrow_op/gold/test3.out b/tests/xpath_arrow_op/gold/test3.out
new file mode 100644
index 00000000..2d5077b9
--- /dev/null
+++ b/tests/xpath_arrow_op/gold/test3.out
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <one>CD</one>
+ <two>ABCDEF, hi there</two>
+</result>
diff --git a/tests/xpath_arrow_op/test1.xsl b/tests/xpath_arrow_op/test1.xsl
new file mode 100644
index 00000000..1066f358
--- /dev/null
+++ b/tests/xpath_arrow_op/test1.xsl
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- An XSLT 3.0 test case, to test XPath 3.1 operator "=>" -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <result>
+ <one>
+ <xsl:value-of select="'abc' => upper-case()"/>
+ </one>
+ <two>
+ <xsl:value-of select="'mnopqr abc' => contains('abc')"/>
+ </two>
+ <three>
+ <xsl:value-of select="'mnopqr' => contains('abc')"/>
+ </three>
+ <four>
+ <xsl:for-each select="'abc pqr' => tokenize('\s+')">
+ <item>
+ <xsl:value-of select="."/>
+ </item>
+ </xsl:for-each>
+ </four>
+ </result>
+ </xsl:template>
+
+ <!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+</xsl:stylesheet>
diff --git a/tests/xpath_arrow_op/test2.xsl b/tests/xpath_arrow_op/test2.xsl
new file mode 100644
index 00000000..bd4b4b35
--- /dev/null
+++ b/tests/xpath_arrow_op/test2.xsl
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- An XSLT 3.0 test case, to test XPath 3.1 operator "=>" -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <result>
+ <xsl:value-of select="concat('abc', 'def', 'ghi') => upper-case()"/>
+ </result>
+ </xsl:template>
+
+ <!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+</xsl:stylesheet>
diff --git a/tests/xpath_arrow_op/test3.xsl b/tests/xpath_arrow_op/test3.xsl
new file mode 100644
index 00000000..478c19e9
--- /dev/null
+++ b/tests/xpath_arrow_op/test3.xsl
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- An XSLT 3.0 test case, to test XPath 3.1 operator "=>" -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <result>
+ <one>
+ <xsl:value-of select="concat('abcde', 'fghij', 'klmno') => upper-case() => substring(3, 2)"/>
+ </one>
+ <two>
+ <xsl:variable name="string" select="'abcdef'"/>
+ <xsl:value-of select="$string => upper-case() => concat(', hi there')"/>
+ </two>
+ </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>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xalan.apache.org
For additional commands, e-mail: commits-help@xalan.apache.org