[prev in list] [next in list] [prev in thread] [next in thread]
List: xalan-cvs
Subject: [xalan-java] branch xalan-j_xslt3.0 updated: committing improvements to implementation of xpath 3.1
From: mukulg () apache ! org
Date: 2023-05-22 16:54:03
Message-ID: 168477444364.3505061.11156971050451718114 () gitbox2-he-fi ! apache ! org
[Download RAW message or body]
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 def4472b committing improvements to implementation of xpath 3.1 fn:tokenize \
function, and related codebase changes. also implementing xpath 3.1 function \
fn:unparsed-text.. def4472b is described below
commit def4472b3d5215e81f974ddd80c3c8ef49b00401
Author: Mukul Gandhi <gandhi.mukul@gmail.com>
AuthorDate: Mon May 22 22:23:27 2023 +0530
committing improvements to implementation of xpath 3.1 fn:tokenize function, and \
related codebase changes. also implementing xpath 3.1 function \
fn:unparsed-text..
---
src/org/apache/xalan/templates/ElemForEach.java | 57 ++++++--
src/org/apache/xalan/templates/ElemValueOf.java | 3 +-
src/org/apache/xalan/templates/ElemVariable.java | 18 +++
src/org/apache/xalan/templates/ElemWithParam.java | 22 ++-
src/org/apache/xpath/compiler/FunctionTable.java | 9 +-
src/org/apache/xpath/compiler/Keywords.java | 3 +
src/org/apache/xpath/functions/FuncConcat.java | 56 ++++++--
.../apache/xpath/functions/FuncUnparsedText.java | 151 +++++++++++++++++++++
src/org/apache/xpath/res/XPATHErrorResources.java | 5 +
9 files changed, 292 insertions(+), 32 deletions(-)
diff --git a/src/org/apache/xalan/templates/ElemForEach.java \
b/src/org/apache/xalan/templates/ElemForEach.java index eae82f1f..8a413977 100644
--- a/src/org/apache/xalan/templates/ElemForEach.java
+++ b/src/org/apache/xalan/templates/ElemForEach.java
@@ -38,6 +38,7 @@ import org.apache.xpath.XPathContext;
import org.apache.xpath.functions.Function;
import org.apache.xpath.objects.ResultSequence;
import org.apache.xpath.objects.XObject;
+import org.apache.xpath.operations.Variable;
import java.io.ObjectInputStream;
import java.io.IOException;
@@ -338,26 +339,29 @@ public class ElemForEach extends ElemTemplateElement implements \
ExpressionOwner XPathContext xctxt = transformer.getXPathContext();
if (m_selectExpression instanceof Function) {
+ // evaluate an xslt/xpath function reference.
+ // for example,
+ // <xsl:for-each select="tokenize(..)"> ...
XObject evalResult = ((Function)m_selectExpression).execute(xctxt);
if (evalResult instanceof ResultSequence) {
- ResultSequence resultSeq = (ResultSequence)evalResult;
- List<XObject> resultSeqItems = resultSeq.getResultSequenceItems();
- for (int idx = 0; idx < resultSeqItems.size(); idx++) {
- XObject resultSeqItem = resultSeqItems.get(idx);
- xctxt.setXPath3ContextItem(resultSeqItem);
-
- for (ElemTemplateElement elemTemplateElem = this.m_firstChild; \
elemTemplateElem != null;
- elemTemplateElem = \
elemTemplateElem.m_nextSibling) {
- xctxt.setSAXLocator(elemTemplateElem);
- transformer.setCurrentElement(elemTemplateElem);
- elemTemplateElem.execute(transformer);
- }
- }
-
+ processResultSequence(transformer, xctxt, evalResult);
return;
}
}
+ if (m_selectExpression instanceof Variable) {
+ // evaluate an xslt variable reference.
+ // for example,
+ // <xsl:variable name="tokens" select="tokenize(..)"/>
+ // <xsl:for-each select="$tokens"> ...
+ XObject evalResult = ((Variable)m_selectExpression).execute(xctxt);
+ if (evalResult instanceof ResultSequence) {
+ processResultSequence(transformer, xctxt, evalResult);
+ return;
+ }
+ }
+
+ // process the node-set, with body of xsl:for-each element as usual
final int sourceNode = xctxt.getCurrentNode();
DTMIterator sourceNodes = m_selectExpression.asIterator(xctxt, sourceNode);
@@ -577,4 +581,29 @@ public class ElemForEach extends ElemTemplateElement implements \
ExpressionOwner os.defaultReadObject();
m_xpath = null;
}
+
+ /*
+ * Process each of the XDM items in order, stored within a 'ResultSequence'
+ * object, with the body of xsl:for-each element.
+ */
+ private void processResultSequence(TransformerImpl transformer,
+ XPathContext xctxt, XObject evalResult)
+ throws \
TransformerException { +
+ ResultSequence resultSeq = (ResultSequence)evalResult;
+ List<XObject> resultSeqItems = resultSeq.getResultSequenceItems();
+
+ for (int idx = 0; idx < resultSeqItems.size(); idx++) {
+ XObject resultSeqItem = resultSeqItems.get(idx);
+ xctxt.setXPath3ContextItem(resultSeqItem);
+
+ for (ElemTemplateElement elemTemplateElem = this.m_firstChild; \
elemTemplateElem != null; + \
elemTemplateElem = elemTemplateElem.m_nextSibling) { + \
xctxt.setSAXLocator(elemTemplateElem); + \
transformer.setCurrentElement(elemTemplateElem); + \
elemTemplateElem.execute(transformer); + }
+ }
+ }
+
}
diff --git a/src/org/apache/xalan/templates/ElemValueOf.java \
b/src/org/apache/xalan/templates/ElemValueOf.java index d32e6a80..96375ddc 100644
--- a/src/org/apache/xalan/templates/ElemValueOf.java
+++ b/src/org/apache/xalan/templates/ElemValueOf.java
@@ -265,14 +265,13 @@ public class ElemValueOf extends ElemTemplateElement
XObject obj = expr.execute(xctxt);
transformer.getTraceManager().fireSelectedEvent(current, this,
- "select", m_selectExpression, obj);
+ "select", m_selectExpression, \
obj); obj.dispatchCharactersEvents(rth);
}
else
{
XObject xpath3ContextItem = xctxt.getXPath3ContextItem();
if (m_isDot && xpath3ContextItem != null) {
- // this is currently, limited to work with xsl:for-each \
instruction xpath3ContextItem.dispatchCharactersEvents(rth);
}
else {
diff --git a/src/org/apache/xalan/templates/ElemVariable.java \
b/src/org/apache/xalan/templates/ElemVariable.java index d6d19b9a..21be5846 100644
--- a/src/org/apache/xalan/templates/ElemVariable.java
+++ b/src/org/apache/xalan/templates/ElemVariable.java
@@ -25,8 +25,11 @@ import javax.xml.transform.TransformerException;
import org.apache.xalan.res.XSLTErrorResources;
import org.apache.xalan.transformer.TransformerImpl;
import org.apache.xml.utils.QName;
+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.objects.ResultSequence;
import org.apache.xpath.objects.XNodeSetForDOM;
import org.apache.xpath.objects.XObject;
import org.apache.xpath.objects.XRTreeFrag;
@@ -271,6 +274,9 @@ public class ElemVariable extends ElemTemplateElement
{
XObject var;
+
+ final XPathContext xctxtOriginal = transformer.getXPathContext();
+
XPathContext xctxt = transformer.getXPathContext();
xctxt.pushCurrentNode(sourceNode);
@@ -279,6 +285,15 @@ public class ElemVariable extends ElemTemplateElement
{
if (null != m_selectPattern)
{
+ Expression selectExpression = m_selectPattern.getExpression();
+ if (selectExpression instanceof Function) {
+ XObject evalResult = ((Function)selectExpression).execute(xctxt);
+ if (evalResult instanceof ResultSequence) {
+ var = evalResult;
+ return var;
+ }
+ }
+
var = m_selectPattern.execute(xctxt, sourceNode, this);
var.allowDetachToRelease(false);
@@ -327,6 +342,9 @@ public class ElemVariable extends ElemTemplateElement
{
xctxt.popCurrentNode();
}
+
+ // restoring the original xpath context, on the xslt transformer object.
+ transformer.setXPathContext(xctxtOriginal);
return var;
}
diff --git a/src/org/apache/xalan/templates/ElemWithParam.java \
b/src/org/apache/xalan/templates/ElemWithParam.java index 71fe8e15..67d72803 100644
--- a/src/org/apache/xalan/templates/ElemWithParam.java
+++ b/src/org/apache/xalan/templates/ElemWithParam.java
@@ -61,6 +61,11 @@ public class ElemWithParam extends ElemTemplateElement
* @serial
*/
private XPath m_selectPattern = null;
+
+ /**
+ * True if the pattern is a simple ".".
+ */
+ private boolean m_isDot = false;
/**
* Set the "select" attribute.
@@ -71,7 +76,13 @@ public class ElemWithParam extends ElemTemplateElement
*/
public void setSelect(XPath v)
{
- m_selectPattern = v;
+ m_selectPattern = v;
+
+ if (v != null) {
+ String s = v.getPatternString();
+
+ m_isDot = (null != s) && s.equals(".");
+ }
}
/**
@@ -202,7 +213,14 @@ public class ElemWithParam extends ElemTemplateElement
{
if (null != m_selectPattern)
{
- var = m_selectPattern.execute(xctxt, sourceNode, this);
+ XObject xpath3ContextItem = xctxt.getXPath3ContextItem();
+
+ if (m_isDot && xpath3ContextItem != null) {
+ var = xpath3ContextItem;
+ }
+ else {
+ var = m_selectPattern.execute(xctxt, sourceNode, this);
+ }
var.allowDetachToRelease(false);
diff --git a/src/org/apache/xpath/compiler/FunctionTable.java \
b/src/org/apache/xpath/compiler/FunctionTable.java index dfa19f14..cefc1b7b 100644
--- a/src/org/apache/xpath/compiler/FunctionTable.java
+++ b/src/org/apache/xpath/compiler/FunctionTable.java
@@ -152,6 +152,9 @@ public class FunctionTable
/** The 'tokenize()' id. */
public static final int FUNC_TOKENIZE = 43;
+
+ /** The 'unparsed-text()' id. */
+ public static final int FUNC_UNPARSED_TEXT = 44;
// Proprietary
@@ -180,7 +183,7 @@ public class FunctionTable
* Number of built in functions. Be sure to update this as
* built-in functions are added.
*/
- private static final int NUM_BUILT_IN_FUNCS = 44;
+ private static final int NUM_BUILT_IN_FUNCS = 45;
/**
* Number of built-in functions that may be added.
@@ -260,6 +263,8 @@ public class FunctionTable
org.apache.xalan.templates.FuncRegexGroup.class;
m_functions[FUNC_TOKENIZE] =
org.apache.xpath.functions.FuncTokenize.class;
+ m_functions[FUNC_UNPARSED_TEXT] =
+ org.apache.xpath.functions.FuncUnparsedText.class;
}
static{
@@ -347,6 +352,8 @@ public class FunctionTable
new Integer(FunctionTable.FUNC_REGEX_GROUP));
m_functionID.put(Keywords.FUNC_TOKENIZE,
new Integer(FunctionTable.FUNC_TOKENIZE));
+ m_functionID.put(Keywords.FUNC_UNPARSED_TEXT,
+ new Integer(FunctionTable.FUNC_UNPARSED_TEXT));
}
public FunctionTable(){
diff --git a/src/org/apache/xpath/compiler/Keywords.java \
b/src/org/apache/xpath/compiler/Keywords.java index d303646f..1ebfaec8 100644
--- a/src/org/apache/xpath/compiler/Keywords.java
+++ b/src/org/apache/xpath/compiler/Keywords.java
@@ -228,6 +228,9 @@ public class Keywords
/** tokenize function string. */
public static final String FUNC_TOKENIZE = "tokenize";
+
+ /** unparsed-text function string. */
+ public static final String FUNC_UNPARSED_TEXT = "unparsed-text";
// Proprietary, built in functions
diff --git a/src/org/apache/xpath/functions/FuncConcat.java \
b/src/org/apache/xpath/functions/FuncConcat.java index 4099225c..6c46f245 100644
--- a/src/org/apache/xpath/functions/FuncConcat.java
+++ b/src/org/apache/xpath/functions/FuncConcat.java
@@ -20,13 +20,18 @@
*/
package org.apache.xpath.functions;
+import javax.xml.transform.TransformerException;
+
import org.apache.xalan.res.XSLMessages;
+import org.apache.xpath.Expression;
import org.apache.xpath.XPathContext;
+import org.apache.xpath.axes.SelfIteratorNoPredicate;
import org.apache.xpath.objects.XObject;
import org.apache.xpath.objects.XString;
/**
- * Execute the Concat() function.
+ * Execute the concat() function.
+ *
* @xsl.usage advanced
*/
public class FuncConcat extends FunctionMultiArgs
@@ -34,8 +39,9 @@ public class FuncConcat extends FunctionMultiArgs
static final long serialVersionUID = 1737228885202314413L;
/**
- * Execute the function. The function must return
+ * Execute the function. The function must return
* a valid object.
+ *
* @param xctxt The current execution context.
* @return A valid XObject.
*
@@ -44,21 +50,20 @@ public class FuncConcat extends FunctionMultiArgs
public XObject execute(XPathContext xctxt) throws \
javax.xml.transform.TransformerException {
- StringBuffer sb = new StringBuffer();
+ StringBuffer sb = new StringBuffer();
// Compiler says we must have at least two arguments.
- sb.append(m_arg0.execute(xctxt).str());
- sb.append(m_arg1.execute(xctxt).str());
+ sb.append(inspectSelfAxesExpression(m_arg0, xctxt));
+ sb.append(inspectSelfAxesExpression(m_arg1, xctxt));
- if (null != m_arg2)
- sb.append(m_arg2.execute(xctxt).str());
+ if (m_arg2 != null) {
+ sb.append(inspectSelfAxesExpression(m_arg2, xctxt));
+ }
- if (null != m_args)
- {
- for (int i = 0; i < m_args.length; i++)
- {
- sb.append(m_args[i].execute(xctxt).str());
- }
+ if (m_args != null) {
+ for (int i = 0; i < m_args.length; i++) {
+ sb.append(inspectSelfAxesExpression(m_args[i], xctxt));
+ }
}
return new XString(sb.toString());
@@ -87,4 +92,29 @@ public class FuncConcat extends FunctionMultiArgs
protected void reportWrongNumberArgs() throws WrongNumberArgsException {
throw new WrongNumberArgsException(XSLMessages.createXPATHMessage("gtone", \
null)); }
+
+ /*
+ * If the expression's pattern string is ".", the evaluation result of expression,
+ * is the string value of XPath context item.
+ */
+ private String inspectSelfAxesExpression(Expression expr, XPathContext xctxt)
+ throws \
TransformerException { + String resultStr = null;
+
+ XObject xpath3ContextItem = xctxt.getXPath3ContextItem();
+ if (expr instanceof SelfIteratorNoPredicate) {
+ if (xpath3ContextItem != null) {
+ resultStr = xpath3ContextItem.str();
+ }
+ else {
+ resultStr = expr.execute(xctxt).str();
+ }
+ }
+ else {
+ resultStr = expr.execute(xctxt).str();
+ }
+
+ return resultStr;
+
+ }
}
diff --git a/src/org/apache/xpath/functions/FuncUnparsedText.java \
b/src/org/apache/xpath/functions/FuncUnparsedText.java new file mode 100644
index 00000000..334c31f3
--- /dev/null
+++ b/src/org/apache/xpath/functions/FuncUnparsedText.java
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+/*
+ * $Id$
+ */
+package org.apache.xpath.functions;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+
+import javax.xml.transform.SourceLocator;
+
+import org.apache.xalan.res.XSLMessages;
+import org.apache.xml.utils.XMLString;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.objects.XString;
+import org.apache.xpath.res.XPATHErrorResources;
+
+/**
+ * Execute the unparsed-text() function.
+ *
+ * This function is designed, to read from an external resource (for example, a \
file) + * and returns a string representation of the resource.
+ *
+ * @author Mukul Gandhi <mukulg@apache.org>
+ *
+ * @xsl.usage advanced
+ */
+public class FuncUnparsedText extends Function2Args {
+
+ private static final long serialVersionUID = 1760543978696171233L;
+
+ private static final String FUNCTION_NAME = "unparsed-text()";
+
+ /**
+ * Execute the function. The function must return a valid object.
+ *
+ * @param xctxt The current execution context.
+ * @return A valid XObject.
+ *
+ * @throws javax.xml.transform.TransformerException
+ */
+ public XObject execute(XPathContext xctxt) throws \
javax.xml.transform.TransformerException + {
+ XObject result = null;
+
+ SourceLocator srcLocator = xctxt.getSAXLocator();
+
+ XMLString href = m_arg0.execute(xctxt).xstr();
+
+ String encodingStr = null;
+
+ if (m_arg1 != null) {
+ XMLString encoding = m_arg1.execute(xctxt).xstr();
+ encodingStr = encoding.toString();
+ if (!("utf-8".equalsIgnoreCase(encodingStr) || \
"utf-16".equalsIgnoreCase(encodingStr))) { + throw new \
javax.xml.transform.TransformerException("FOUT1190 : The value of the 'encoding' \
argument " + + "is not a valid \
encoding name. Allowed encoding names are " + \
+ "UTF-8 and UTF-16.", srcLocator); + }
+ }
+
+ try {
+ String urlContents = readDataFromUrl(new URL(href.toString()), \
encodingStr); + String resultStr = null;
+ if (encodingStr != null) {
+ resultStr = new String(urlContents.getBytes(), \
encodingStr.toUpperCase()); + }
+ else {
+ resultStr = urlContents;
+ }
+
+ result = new XString(resultStr);
+ }
+ catch (IOException ex) {
+ throw new javax.xml.transform.TransformerException(ex.getMessage(), \
srcLocator); + }
+
+ return result;
+
+ }
+
+
+
+ /**
+ * Check that the number of arguments passed to this function is correct.
+ *
+ * @param argNum The number of arguments that is being passed to the function.
+ *
+ * @throws WrongNumberArgsException
+ */
+ public void checkNumberArgs(int argNum) throws WrongNumberArgsException
+ {
+ if (argNum > 2) {
+ reportWrongNumberArgs();
+ }
+ }
+
+ /**
+ * Constructs and throws a WrongNumberArgException with the appropriate
+ * message for this function object.
+ *
+ * @throws WrongNumberArgsException
+ */
+ protected void reportWrongNumberArgs() throws WrongNumberArgsException {
+ throw new WrongNumberArgsException(XSLMessages.createXPATHMessage(
+ XPATHErrorResources.ER_ONE_OR_TWO, \
null)); //"1 or 2" + }
+
+ /*
+ * Read the string contents from a url.
+ */
+ private String readDataFromUrl(URL url, String encodingStr) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ String inpLine;
+
+ InputStream inpStream = url.openStream();
+
+ try {
+ BufferedReader buffReader = new BufferedReader(new \
InputStreamReader(inpStream)); + int chr;
+ while ((chr = buffReader.read()) != -1) {
+ sb.append((char)chr);
+ }
+ } finally {
+ inpStream.close();
+ }
+
+ return sb.toString();
+ }
+
+}
diff --git a/src/org/apache/xpath/res/XPATHErrorResources.java \
b/src/org/apache/xpath/res/XPATHErrorResources.java index 75af7bcb..8dd71cd2 100644
--- a/src/org/apache/xpath/res/XPATHErrorResources.java
+++ b/src/org/apache/xpath/res/XPATHErrorResources.java
@@ -228,6 +228,8 @@ public static final String ER_IGNORABLE_WHITESPACE_NOT_HANDLED =
/** The FastStringBuffer argument can not be null */
public static final String ER_FASTSTRINGBUFFER_CANNOT_BE_NULL =
"ER_FASTSTRINGBUFFER_CANNOT_BE_NULL";
+ /** 1 or 2 */
+ public static final String ER_ONE_OR_TWO = "ER_ONE_OR_TWO";
/** 2 or 3 */
public static final String ER_TWO_OR_THREE = "ER_TWO_OR_THREE";
/** 1, 2 or 3 */
@@ -622,6 +624,9 @@ public static final String ER_IGNORABLE_WHITESPACE_NOT_HANDLED =
{ ER_FASTSTRINGBUFFER_CANNOT_BE_NULL,
"The FastStringBuffer argument can not be null"},
+ { ER_ONE_OR_TWO,
+ "1 or 2"},
+
{ ER_TWO_OR_THREE,
"2 or 3"},
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xalan.apache.org
For additional commands, e-mail: commits-help@xalan.apache.org
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic