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/07/02 10:47:09 UTC
[xalan-java] branch xalan-j_xslt3.0 updated: committing improvements to xpath 3.1 function item inline function expressions processing. improvements to, xsl:copy-of instruction to handle processing of xpath 3.1 sequences. improvements to xpath function fn:count to handle range to expression as an argument. adding a related working xslt 3.0 test case as well.
This is an automated email from the ASF dual-hosted git repository.
mukulg pushed a commit to branch xalan-j_xslt3.0
in repository https://gitbox.apache.org/repos/asf/xalan-java.git
The following commit(s) were added to refs/heads/xalan-j_xslt3.0 by this push:
new 76dfa805 committing improvements to xpath 3.1 function item inline function expressions processing. improvements to, xsl:copy-of instruction to handle processing of xpath 3.1 sequences. improvements to xpath function fn:count to handle range to expression as an argument. adding a related working xslt 3.0 test case as well.
new af5aec06 Merge pull request #16 from mukulga/xalan-j_xslt3.0_mukul
76dfa805 is described below
commit 76dfa805c35c7c32dee36b3b10ed7e29a1971d96
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Sun Jul 2 16:07:31 2023 +0530
committing improvements to xpath 3.1 function item inline function expressions processing. improvements to, xsl:copy-of instruction to handle processing of xpath 3.1 sequences. improvements to xpath function fn:count to handle range to expression as an argument. adding a related working xslt 3.0 test case as well.
---
src/org/apache/xalan/templates/ElemCopyOf.java | 61 ++++++++++++------------
src/org/apache/xpath/compiler/XPathParser.java | 37 ++++++++++++--
src/org/apache/xpath/functions/FuncCount.java | 13 +++--
src/org/apache/xpath/functions/FuncFilter.java | 2 +-
tests/fn_filter/gold/test7.out | 4 ++
tests/fn_filter/test7.xsl | 38 +++++++++++++++
tests/org/apache/xalan/xpath3/FnFilterTests.java | 10 ++++
7 files changed, 126 insertions(+), 39 deletions(-)
diff --git a/src/org/apache/xalan/templates/ElemCopyOf.java b/src/org/apache/xalan/templates/ElemCopyOf.java
index d0889369..0c9876f3 100644
--- a/src/org/apache/xalan/templates/ElemCopyOf.java
+++ b/src/org/apache/xalan/templates/ElemCopyOf.java
@@ -38,7 +38,8 @@ import org.apache.xpath.objects.XObject;
/*
* Implementation of XSLT xsl:copy-of instruction.
*
- * XSLT 3.0 xsl:copy-of instruction definition,
+ * XSLT 3.0 spec, provides following definition of xsl:copy-of
+ * instruction,
*
* <xsl:copy-of
select = expression
@@ -51,7 +52,7 @@ import org.apache.xpath.objects.XObject;
*/
public class ElemCopyOf extends ElemTemplateElement
{
- static final long serialVersionUID = -7433828829497411127L;
+ static final long serialVersionUID = -7433828829497411127L;
/**
* The required select attribute contains an expression.
@@ -119,8 +120,7 @@ public class ElemCopyOf extends ElemTemplateElement
/**
* The xsl:copy-of element can be used to insert a result tree
* fragment into the result tree, without first converting it to
- * a string as xsl:value-of does (see [7.6.1 Generating Text with
- * xsl:value-of]).
+ * a string as xsl:value-of does.
*
* @param transformer non-null reference to the the current transform-time state.
*
@@ -145,8 +145,7 @@ public class ElemCopyOf extends ElemTemplateElement
SerializationHandler handler = transformer.getSerializationHandler();
- if (null != value)
- {
+ if (value != null) {
int type = value.getType();
String s;
@@ -199,45 +198,47 @@ public class ElemCopyOf extends ElemTemplateElement
handler, value, transformer.getXPathContext());
break;
case XObject.CLASS_RESULT_SEQUENCE :
- // added for XSLT 3.0
+ // added for XSLT 3.0
ResultSequence resultSequence = (ResultSequence)value;
char[] spaceCharArr = new char[1];
spaceCharArr[0] = ' ';
- for (int idx = 0; idx < resultSequence.size(); idx++) {
+
+ for (int idx = 0; idx < resultSequence.size(); idx++) {
XObject sequenceItem = resultSequence.item(idx);
if (sequenceItem.getType() == XObject.CLASS_STRING) {
String str = sequenceItem.str();
handler.characters(str.toCharArray(), 0, str.length());
if (idx < (resultSequence.size() - 1)) {
- handler.characters(spaceCharArr, 0, 1);
+ handler.characters(spaceCharArr, 0, 1);
}
- continue;
}
-
- DTMIterator dtmIter = sequenceItem.iter();
-
- DTMTreeWalker dtmTreeWalker = new TreeWalker2Result(transformer, handler);
- int nodePos;
+ else if (sequenceItem.getType() == XObject.CLASS_NODESET) {
+ DTMIterator nl1 = sequenceItem.iter();
- while (DTM.NULL != (nodePos = dtmIter.nextNode())) {
- DTM dtm = xctxt.getDTMManager().getDTM(nodePos);
- short t = dtm.getNodeType(nodePos);
+ DTMTreeWalker tw1 = new TreeWalker2Result(transformer, handler);
+ int pos1;
- if (t == DTM.DOCUMENT_NODE) {
- for (int child = dtm.getFirstChild(nodePos); child != DTM.NULL;
- child = dtm.getNextSibling(child)) {
- dtmTreeWalker.traverse(child);
- }
- }
- else if (t == DTM.ATTRIBUTE_NODE) {
- SerializerUtils.addAttribute(handler, nodePos);
- }
- else {
- dtmTreeWalker.traverse(nodePos);
- }
+ while (DTM.NULL != (pos1 = nl1.nextNode())) {
+ DTM dtm = xctxt.getDTMManager().getDTM(pos1);
+ short t = dtm.getNodeType(pos1);
+
+ if (t == DTM.DOCUMENT_NODE) {
+ for (int child = dtm.getFirstChild(pos1); child != DTM.NULL;
+ child = dtm.getNextSibling(child)) {
+ tw1.traverse(child);
+ }
+ }
+ else if (t == DTM.ATTRIBUTE_NODE) {
+ SerializerUtils.addAttribute(handler, pos1);
+ }
+ else {
+ tw1.traverse(pos1);
+ }
+ }
}
}
+
break;
default :
diff --git a/src/org/apache/xpath/compiler/XPathParser.java b/src/org/apache/xpath/compiler/XPathParser.java
index 3b49f83a..1aea175c 100644
--- a/src/org/apache/xpath/compiler/XPathParser.java
+++ b/src/org/apache/xpath/compiler/XPathParser.java
@@ -21,6 +21,7 @@
package org.apache.xpath.compiler;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import javax.xml.transform.ErrorListener;
@@ -76,6 +77,16 @@ public class XPathParser
protected final static int FILTER_MATCH_PRIMARY = 1;
protected final static int FILTER_MATCH_PREDICATES = 2;
+ /*
+ * While parsing XPath 3.1 "function item" inline function expressions, we use this
+ * constant string array to make parse decisions. The elements of this array are certain
+ * XPath operator names that need this support.
+ */
+ static final String[] XPATH_INLINE_FN_OP_ARR = new String[] {"div", "or", "and", "mod", "to",
+ "eq", "ne", "lt", "gt", "le", "ge"};
+
+ List<String> fXpathInlineFunctionOpTokensList = null;
+
static InlineFunction fInlineFunction = null;
/**
@@ -85,6 +96,7 @@ public class XPathParser
{
m_errorListener = errorListener;
m_sourceLocator = sourceLocator;
+ fXpathInlineFunctionOpTokensList = Arrays.asList(XPATH_INLINE_FN_OP_ARR);
}
/**
@@ -1626,6 +1638,15 @@ public class XPathParser
consumeExpected('{');
+ // While parsing the XPath expression string that forms body of inline
+ // function expression, we only get this XPath expression's string value,
+ // as determined below and store that within an object of class
+ // 'InlineFunction', which is later used during evaluation of XPath 3.1
+ // higher-order functions like fn:for-each, fn:filter.
+ // This seems to be unlike all other XPath expression parsing (i.e, not involving
+ // the function item inline function expressions) implemented by XalanJ's XPath 1.0
+ // processor that uses this XPathParser class.
+
List<String> funcBodyXPathExprStrPartsList = new ArrayList<String>();
if (tokenIs('}')) {
@@ -1647,22 +1668,28 @@ public class XPathParser
for (int idx = 0; idx < funcBodyXPathExprStrPartsArr.length; idx++) {
String xpathExprStrPart = null;
+ boolean isXpathInlineFunctionOpToken = false;
+
if ("$".equals(funcBodyXPathExprStrPartsArr[idx]) && (idx <
(funcBodyXPathExprStrPartsArr.length - 1))) {
+ // this handles, variable references within XPath expression inline function's body
xpathExprStrPart = "$" + funcBodyXPathExprStrPartsArr[idx + 1];
idx += 1;
}
- else {
- xpathExprStrPart = (String)funcBodyXPathExprStrPartsArr[idx];
+ else {
+ xpathExprStrPart = (String)funcBodyXPathExprStrPartsArr[idx];
+ if (fXpathInlineFunctionOpTokensList.contains(xpathExprStrPart)) {
+ isXpathInlineFunctionOpToken = true;
+ }
}
- funcBodyXPathExprStrBuff.append(xpathExprStrPart + " ");
+ funcBodyXPathExprStrBuff.append(isXpathInlineFunctionOpToken ? " " + xpathExprStrPart +
+ " " : xpathExprStrPart);
}
- funcBodyXPathExprStr = funcBodyXPathExprStrBuff.toString();
+ funcBodyXPathExprStr = (funcBodyXPathExprStrBuff.toString()).trim();
if (funcBodyXPathExprStr.length() > 0) {
- funcBodyXPathExprStr = funcBodyXPathExprStr.substring(0, funcBodyXPathExprStr.length() - 1);
inlineFunction.setFuncBodyXPathExprStr(funcBodyXPathExprStr);
}
diff --git a/src/org/apache/xpath/functions/FuncCount.java b/src/org/apache/xpath/functions/FuncCount.java
index 3ca8f438..074c33d0 100644
--- a/src/org/apache/xpath/functions/FuncCount.java
+++ b/src/org/apache/xpath/functions/FuncCount.java
@@ -27,6 +27,7 @@ import org.apache.xpath.objects.ResultSequence;
import org.apache.xpath.objects.XNodeSet;
import org.apache.xpath.objects.XNumber;
import org.apache.xpath.objects.XObject;
+import org.apache.xpath.operations.Range;
import org.apache.xpath.operations.Variable;
/**
@@ -69,9 +70,15 @@ public class FuncCount extends FunctionOneArg
}
}
else if (m_arg0 instanceof Expression) {
- DTMIterator nl = m_arg0.asIterator(xctxt, xctxt.getCurrentNode());
- count = nl.getLength();
- nl.detach();
+ if (m_arg0 instanceof Range) {
+ ResultSequence resultSeq = (ResultSequence)(((Range)m_arg0).execute(xctxt));
+ count = resultSeq.size();
+ }
+ else {
+ DTMIterator nl = m_arg0.asIterator(xctxt, xctxt.getCurrentNode());
+ count = nl.getLength();
+ nl.detach();
+ }
}
return new XNumber((double)count);
diff --git a/src/org/apache/xpath/functions/FuncFilter.java b/src/org/apache/xpath/functions/FuncFilter.java
index 933ce64e..995f47ed 100644
--- a/src/org/apache/xpath/functions/FuncFilter.java
+++ b/src/org/apache/xpath/functions/FuncFilter.java
@@ -220,7 +220,7 @@ public class FuncFilter extends Function2Args {
int dtmNodeHandle;
- while (DTM.NULL != (dtmNodeHandle = arg0DtmIterator.nextNode())) {
+ while (DTM.NULL != (dtmNodeHandle = arg0DtmIterator.nextNode())) {
XNodeSet inpSeqItem = new XNodeSet(dtmNodeHandle, xctxt.getDTMManager());
if (varQname != null) {
inlineFunctionVarMap.put(varQname, inpSeqItem);
diff --git a/tests/fn_filter/gold/test7.out b/tests/fn_filter/gold/test7.out
new file mode 100644
index 00000000..a0d9cd9f
--- /dev/null
+++ b/tests/fn_filter/gold/test7.out
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <a>5</a>
+ <a>6</a>
+</result>
diff --git a/tests/fn_filter/test7.xsl b/tests/fn_filter/test7.xsl
new file mode 100644
index 00000000..21b33eaf
--- /dev/null
+++ b/tests/fn_filter/test7.xsl
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- use with test1_a.xml -->
+
+ <!-- Test for the XPath 3.1 fn:filter() function -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/elem">
+ <result>
+ <xsl:variable name="func1" select="function($x) { count(3 to $x) lt 5 }"/>
+ <xsl:copy-of select="filter(a, $func1)"/>
+ </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/org/apache/xalan/xpath3/FnFilterTests.java b/tests/org/apache/xalan/xpath3/FnFilterTests.java
index 67b9e53e..c322935f 100644
--- a/tests/org/apache/xalan/xpath3/FnFilterTests.java
+++ b/tests/org/apache/xalan/xpath3/FnFilterTests.java
@@ -109,5 +109,15 @@ public class FnFilterTests extends XslTransformTestsUtil {
runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath,
new XslTestsErrorHandler());
}
+
+ @Test
+ public void xslFnFilterTest7() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test7.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test7.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xalan.apache.org
For additional commands, e-mail: commits-help@xalan.apache.org