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 2025/04/04 11:41:41 UTC
(xalan-java) branch xalan-j_xslt3.0_mvn updated: committing implementation improvements to xalan-j xpath 3.1 function fn:transform, along with a working related test case
This is an automated email from the ASF dual-hosted git repository.
mukulg pushed a commit to branch xalan-j_xslt3.0_mvn
in repository https://gitbox.apache.org/repos/asf/xalan-java.git
The following commit(s) were added to refs/heads/xalan-j_xslt3.0_mvn by this push:
new b05b03d50 committing implementation improvements to xalan-j xpath 3.1 function fn:transform, along with a working related test case
b05b03d50 is described below
commit b05b03d50516d423c74c11a3896111849e8bb8cc
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Fri Apr 4 17:11:27 2025 +0530
committing implementation improvements to xalan-j xpath 3.1 function fn:transform, along with a working related test case
---
README | 6 +-
.../org/apache/xalan/templates/ElemCopyOf.java | 21 ++-
.../apache/xalan/templates/ElemResultDocument.java | 171 ++++++++++++++++++---
.../org/apache/xalan/templates/ElemVariable.java | 3 +-
.../apache/xalan/transformer/TransformerImpl.java | 3 -
.../xalan/transformer/TreeWalker2Result.java | 5 +-
.../org/apache/xpath/functions/FuncTransform.java | 51 +++---
.../apache/xpath/objects/XMLNodeCursorImpl.java | 15 ++
.../xalan/tests/xpath3/FnTransformTests.java | 10 ++
src/test/resources/fn_transform/gold/test10.out | 18 +++
src/test/resources/fn_transform/render.xsl | 23 +++
src/test/resources/fn_transform/render2.xsl | 52 +++++++
src/test/resources/fn_transform/test10.xsl | 68 ++++++++
13 files changed, 393 insertions(+), 53 deletions(-)
diff --git a/README b/README
index 9e5975ee7..5d1b8dd43 100644
--- a/README
+++ b/README
@@ -17,7 +17,7 @@
Copyright 1999-2025 The Apache Software Foundation
-Document last modified : 2025-04-03
+Document last modified : 2025-04-04
Authors:
Gary Gregory <gg...@apache.org>
@@ -59,11 +59,11 @@ This produces Maven build output with trailing information like following:
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running org.apache.xalan.tests.main.AllXsl3Tests
-[INFO] Tests run: 973, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 25.413 s - in org.apache.xalan.tests.main.AllXsl3Tests
+[INFO] Tests run: 974, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 27.743 s - in org.apache.xalan.tests.main.AllXsl3Tests
[INFO]
[INFO] Results:
[INFO]
-[INFO] Tests run: 973, Failures: 0, Errors: 0, Skipped: 0
+[INFO] Tests run: 974, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
diff --git a/src/main/java/org/apache/xalan/templates/ElemCopyOf.java b/src/main/java/org/apache/xalan/templates/ElemCopyOf.java
index d98030718..cad0525b4 100644
--- a/src/main/java/org/apache/xalan/templates/ElemCopyOf.java
+++ b/src/main/java/org/apache/xalan/templates/ElemCopyOf.java
@@ -66,8 +66,6 @@ import xml.xpath31.processor.types.XSUntypedAtomic;
/**
* Implementation of XSLT xsl:copy-of instruction.
*
- * Ref : https://www.w3.org/TR/xslt-30/#element-copy-of
- *
* @author Scott Boag <sc...@us.ibm.com>
* @author Morris Kwan <mk...@apache.org>
* @author Christine Li <jy...@apache.org>
@@ -332,14 +330,25 @@ public class ElemCopyOf extends ElemTemplateElement
public static void copyOfActionOnNodeSet(XMLNodeCursorImpl nodeSet, TransformerImpl transformer,
SerializationHandler serializationHandler, XPathContext xctxt)
throws TransformerException, SAXException {
- DTMCursorIterator dtmIter = nodeSet.iter();
+ DTMCursorIterator dtmIter = nodeSet.iter();
DTMTreeWalker tw = new TreeWalker2Result(transformer, serializationHandler);
int pos;
+
+ DTM dtm1 = nodeSet.getDtm();
- while ((pos = dtmIter.nextNode()) != DTM.NULL) {
- DTM dtm = xctxt.getDTMManager().getDTM(pos);
- short nodeType = dtm.getNodeType(pos);
+ while ((pos = dtmIter.nextNode()) != DTM.NULL) {
+ DTM dtm = null;
+
+ if (dtm1 == null) {
+ dtm = (xctxt.getDTMManager()).getDTM(pos);
+ }
+ else {
+ dtm = dtm1;
+ tw.setDTM(dtm);
+ }
+
+ short nodeType = dtm.getNodeType(pos);
if (nodeType == DTM.DOCUMENT_NODE) {
// From the 1st XML element node child of document node, validate all
diff --git a/src/main/java/org/apache/xalan/templates/ElemResultDocument.java b/src/main/java/org/apache/xalan/templates/ElemResultDocument.java
index b95fa3f68..8a64b7062 100644
--- a/src/main/java/org/apache/xalan/templates/ElemResultDocument.java
+++ b/src/main/java/org/apache/xalan/templates/ElemResultDocument.java
@@ -21,37 +21,47 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Properties;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.SourceLocator;
import javax.xml.transform.TransformerException;
+import javax.xml.transform.dom.DOMSource;
import org.apache.xalan.transformer.TransformerImpl;
import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
import org.apache.xml.dtm.DTM;
import org.apache.xml.dtm.DTMCursorIterator;
+import org.apache.xml.dtm.DTMManager;
import org.apache.xml.utils.QName;
import org.apache.xpath.Expression;
import org.apache.xpath.ExpressionOwner;
import org.apache.xpath.XPathContext;
+import org.apache.xpath.functions.FuncTransform;
import org.apache.xpath.objects.XMLNodeCursorImpl;
import org.apache.xpath.objects.XNodeSetForDOM;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.objects.XPathMap;
import org.apache.xpath.objects.XRTreeFrag;
import org.json.JSONException;
import org.json.JSONObject;
+import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import xml.xpath31.processor.types.XSString;
/**
* Implementation of the XSLT 3.0 xsl:result-document instruction.
*
- * Ref : https://www.w3.org/TR/xslt-30/#element-result-document
- *
* @author Mukul Gandhi <mu...@apache.org>
*
* @xsl.usage advanced
@@ -76,6 +86,24 @@ public class ElemResultDocument extends ElemTemplateElement
*/
private boolean m_omitXmlDeclaration;
+ /**
+ * This URI string value may be set from fn:transform
+ * function call.
+ */
+ public static String m_BaseOutputUriStrAbsValue = null;
+
+ /**
+ * Class field representing reference to, function fn:transform's
+ * return value which is of type XDM map.
+ */
+ public static XPathMap m_fnTransformResult = null;
+
+ /**
+ * Class field representing reference to, function fn:transform's
+ * 'delivery-format' parameter specification.
+ */
+ public static String m_fnTransformDeliveryFormat = null;
+
/**
* The class constructor.
*/
@@ -210,9 +238,15 @@ public class ElemResultDocument extends ElemTemplateElement
URI url = new URI(hrefStrVal);
String stylesheetSystemId = srcLocator.getSystemId(); // base uri of stylesheet, if available
- if (!url.isAbsolute() && (stylesheetSystemId != null)) {
- URI resolvedUriArg = (new URI(stylesheetSystemId)).resolve(hrefStrVal);
- resolvedHrefUrl = resolvedUriArg.toURL();
+ if (!url.isAbsolute()) {
+ if (m_BaseOutputUriStrAbsValue != null) {
+ URI resolvedUriArg = (new URI(m_BaseOutputUriStrAbsValue)).resolve(hrefStrVal);
+ resolvedHrefUrl = resolvedUriArg.toURL();
+ }
+ else if (stylesheetSystemId != null) {
+ URI resolvedUriArg = (new URI(stylesheetSystemId)).resolve(hrefStrVal);
+ resolvedHrefUrl = resolvedUriArg.toURL();
+ }
}
if (resolvedHrefUrl == null) {
@@ -230,7 +264,8 @@ public class ElemResultDocument extends ElemTemplateElement
+ "an absolute uri.", srcLocator);
}
- QName methodQname = m_method; // Optional, with default value "xml"
+ QName methodQname = m_method; // Optional, with default value "xml"
+
boolean omitXmlDeclarationAttr = m_omitXmlDeclaration; // Optional, with default value "false"
String resolvedHrefStrVal = resolvedHrefUrl.toString();
@@ -251,12 +286,43 @@ public class ElemResultDocument extends ElemTemplateElement
xmlStrValue = xmlStrValue.substring(xmlPrologEndStrIndex + 2);
}
- writeStringContentsToFile(resolvedHrefStrVal, xmlStrValue);
+ if (m_fnTransformResult != null) {
+ if (m_BaseOutputUriStrAbsValue != null) {
+ int lastIndexOfSlsh = m_BaseOutputUriStrAbsValue.lastIndexOf('/');
+ String hrefUriPrefix = m_BaseOutputUriStrAbsValue.substring(0, lastIndexOfSlsh + 1);
+ URI url = new URI(hrefStrVal);
+ String effectAbsUri = null;
+ if (!url.isAbsolute()) {
+ effectAbsUri = hrefUriPrefix + url.toString();
+ }
+ else {
+ effectAbsUri = url.toString();
+ }
+
+ m_fnTransformResult.put(new XSString(effectAbsUri), getFnTransformResultComponent(xctxt, xmlStrValue));
+ }
+ else {
+ m_fnTransformResult.put(new XSString(resolvedHrefStrVal), getFnTransformResultComponent(xctxt, xmlStrValue));
+ }
+ }
+ else {
+ writeStringContentsToFile(resolvedHrefStrVal, xmlStrValue);
+ }
}
else if ((Constants.ATTRVAL_OUTPUT_METHOD_TEXT).equals(methodQname.toString())) {
String textStrValue = transformer.transformToString(this);
- writeStringContentsToFile(resolvedHrefStrVal, textStrValue);
+ if (m_fnTransformResult != null) {
+ if (m_BaseOutputUriStrAbsValue != null) {
+ m_fnTransformResult.put(new XSString(m_BaseOutputUriStrAbsValue), getFnTransformResultComponent(xctxt, textStrValue));
+ }
+ else {
+ m_fnTransformResult.put(new XSString(resolvedHrefStrVal), getFnTransformResultComponent(xctxt, textStrValue));
+ }
+ }
+ else {
+ writeStringContentsToFile(resolvedHrefStrVal, textStrValue);
+ }
}
else if ((Constants.ATTRVAL_OUTPUT_METHOD_JSON).equals(methodQname.toString())) {
String jsonStrValue = transformer.transformToString(this);
@@ -269,13 +335,23 @@ public class ElemResultDocument extends ElemTemplateElement
}
catch (JSONException ex) {
throw new TransformerException("XPTY0004 : An xsl:result-document instruction within a stylesheet has attribute "
- + "\"method\" with value 'json'. There's a JSON syntax error within "
- + "an input string provided to the JSON parser, or there was a duplicate "
- + "JSON object key. Following run-time error occured : " +
- ex.getMessage() + ".", srcLocator);
+ + "\"method\" with value 'json'. There's a JSON syntax error within "
+ + "an input string provided to the JSON parser, or there was a duplicate "
+ + "JSON object key. Following run-time error occured : " +
+ ex.getMessage() + ".", srcLocator);
}
- writeStringContentsToFile(resolvedHrefStrVal, jsonStrValue.trim());
+ if (m_fnTransformResult != null) {
+ if (m_BaseOutputUriStrAbsValue != null) {
+ m_fnTransformResult.put(new XSString(m_BaseOutputUriStrAbsValue), getFnTransformResultComponent(xctxt, jsonStrValue.trim()));
+ }
+ else {
+ m_fnTransformResult.put(new XSString(resolvedHrefStrVal), getFnTransformResultComponent(xctxt, jsonStrValue.trim()));
+ }
+ }
+ else {
+ writeStringContentsToFile(resolvedHrefStrVal, jsonStrValue.trim());
+ }
}
else if ((Constants.ATTRVAL_OUTPUT_METHOD_HTML).equals(methodQname.toString())) {
ElemTemplateElement t = this.m_firstChild;
@@ -311,13 +387,34 @@ public class ElemResultDocument extends ElemTemplateElement
String htmlStrValue = XslTransformEvaluationHelper.serializeXmlDomElementNode(node);
int xmlPrologSuffixIdx = htmlStrValue.indexOf("?>");
htmlStrValue = htmlStrValue.substring(xmlPrologSuffixIdx + 2);
+
+ if (m_fnTransformResult != null) {
+ if (m_BaseOutputUriStrAbsValue != null) {
+ int lastIndexOfSlsh = m_BaseOutputUriStrAbsValue.lastIndexOf('/');
+ String hrefUriPrefix = m_BaseOutputUriStrAbsValue.substring(0, lastIndexOfSlsh + 1);
+ URI url = new URI(hrefStrVal);
+ String effectAbsUri = null;
+ if (!url.isAbsolute()) {
+ effectAbsUri = hrefUriPrefix + url.toString();
+ }
+ else {
+ effectAbsUri = url.toString();
+ }
- writeStringContentsToFile(resolvedHrefStrVal, htmlStrValue);
+ m_fnTransformResult.put(new XSString(effectAbsUri), getFnTransformResultComponent(xctxt, htmlStrValue));
+ }
+ else {
+ m_fnTransformResult.put(new XSString(resolvedHrefStrVal), getFnTransformResultComponent(xctxt, htmlStrValue));
+ }
+ }
+ else {
+ writeStringContentsToFile(resolvedHrefStrVal, htmlStrValue);
+ }
/**
* This is an original xsl:output information that has to be restored
* on stylesheetRoot object for any further XSL transformation work, after
- * this xsl:result-document instruction instance has completed executing.
+ * this xsl:result-document instruction instance has completed its processing.
*/
Properties prevOutputProperties = stylesheetRoot.getDefaultOutputProps();
@@ -330,8 +427,8 @@ public class ElemResultDocument extends ElemTemplateElement
}
catch (Exception ex) {
throw new TransformerException("XPTY0004 : An exception occured while evaluating an "
- + "xsl:result-document instruction. Following "
- + "run-time error occured : " + ex.getMessage() + ".", srcLocator);
+ + "xsl:result-document instruction. Following "
+ + "run-time error occured : " + ex.getMessage() + ".", srcLocator);
}
finally {
if (transformer.getDebug()) {
@@ -375,8 +472,8 @@ public class ElemResultDocument extends ElemTemplateElement
}
/**
- * This method creates a physical file specified by its name within
- * local file system store, and writes a string value to the file.
+ * This method creates a file specified by its name within local file system
+ * store, and writes a string value to the file.
*
* @param hrefStr local url of the file, with "file:/" scheme.
* this url may point to any location within
@@ -397,5 +494,41 @@ public class ElemResultDocument extends ElemTemplateElement
fos.flush();
fos.close();
}
+
+ /**
+ * This method definition gets details for the, result of xsl:result-document
+ * instruction.
+ */
+ private XObject getFnTransformResultComponent(XPathContext xctxt, String resultStrValue) throws Exception {
+
+ XObject result = null;
+
+ if ((m_fnTransformDeliveryFormat == null) || (FuncTransform.DOCUMENT).equals(m_fnTransformDeliveryFormat)) {
+ System.setProperty(Constants.XML_DOCUMENT_BUILDER_FACTORY_KEY, Constants.XML_DOCUMENT_BUILDER_FACTORY_VALUE);
+ System.setProperty(FuncTransform.XSLT_TRANSFORMER_FACTORY_KEY, FuncTransform.XSLT_TRANSFORMER_FACTORY_VALUE);
+
+ DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
+ StringReader strReader = new StringReader(resultStrValue);
+ Document document = docBuilder.parse(new InputSource(strReader));
+
+ DTMManager dtmManager = xctxt.getDTMManager();
+ DTM resultDtm = dtmManager.getDTM(new DOMSource(document), true, null, false, false);
+ int resultDtmHandle = resultDtm.getDocument();
+
+ XMLNodeCursorImpl resultNode = new XMLNodeCursorImpl(resultDtmHandle, dtmManager);
+ resultNode.setDtm(resultDtm);
+
+ result = resultNode;
+ }
+ else if ((FuncTransform.SERIALIZED).equals(m_fnTransformDeliveryFormat)) {
+ result = new XSString(resultStrValue);
+ }
+ else if ((FuncTransform.RAW).equals(m_fnTransformDeliveryFormat)) {
+ // TO DO
+ }
+
+ return result;
+ }
}
diff --git a/src/main/java/org/apache/xalan/templates/ElemVariable.java b/src/main/java/org/apache/xalan/templates/ElemVariable.java
index 5a3b6784c..e4d70cf9a 100644
--- a/src/main/java/org/apache/xalan/templates/ElemVariable.java
+++ b/src/main/java/org/apache/xalan/templates/ElemVariable.java
@@ -411,7 +411,8 @@ public class ElemVariable extends ElemTemplateElement
XObject evalResult = ((Function)selectExpression).execute(xctxt);
if ((evalResult instanceof ResultSequence) || (evalResult instanceof XPathMap) ||
(evalResult instanceof XPathArray) ||
- (evalResult instanceof XSAnyType)) {
+ (evalResult instanceof XSAnyType) ||
+ (evalResult instanceof XMLNodeCursorImpl)) {
if (m_asAttr != null) {
evalResult = SequenceTypeSupport.castXdmValueToAnotherType(evalResult, m_asAttr, null, xctxt);
if (evalResult == null) {
diff --git a/src/main/java/org/apache/xalan/transformer/TransformerImpl.java b/src/main/java/org/apache/xalan/transformer/TransformerImpl.java
index f49f17bc7..9542e0413 100644
--- a/src/main/java/org/apache/xalan/transformer/TransformerImpl.java
+++ b/src/main/java/org/apache/xalan/transformer/TransformerImpl.java
@@ -2552,9 +2552,6 @@ public class TransformerImpl extends Transformer
xctxt.popSAXLocator();
}
- // Check for infinite loops if we have to
-// if (check)
-// getStackGuard().pop();
}
/**
diff --git a/src/main/java/org/apache/xalan/transformer/TreeWalker2Result.java b/src/main/java/org/apache/xalan/transformer/TreeWalker2Result.java
index fc180ec7e..8377c5b3a 100644
--- a/src/main/java/org/apache/xalan/transformer/TreeWalker2Result.java
+++ b/src/main/java/org/apache/xalan/transformer/TreeWalker2Result.java
@@ -70,7 +70,10 @@ public class TreeWalker2Result extends DTMTreeWalker
*/
public void traverse(int pos) throws org.xml.sax.SAXException
{
- m_dtm = m_transformer.getXPathContext().getDTM(pos);
+ if (m_dtm == null) {
+ m_dtm = m_transformer.getXPathContext().getDTM(pos);
+ }
+
m_startNode = pos;
super.traverse(pos);
diff --git a/src/main/java/org/apache/xpath/functions/FuncTransform.java b/src/main/java/org/apache/xpath/functions/FuncTransform.java
index 738647f82..c7de3e77e 100644
--- a/src/main/java/org/apache/xpath/functions/FuncTransform.java
+++ b/src/main/java/org/apache/xpath/functions/FuncTransform.java
@@ -36,6 +36,7 @@ import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
+import org.apache.xalan.templates.ElemResultDocument;
import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
import org.apache.xml.dtm.DTM;
import org.apache.xml.dtm.DTMCursorIterator;
@@ -69,31 +70,32 @@ public class FuncTransform extends FunctionDef1Arg
* Definition of various class, constant field definitions.
*/
- private static final String XSLT_TRANSFORMER_FACTORY_KEY = "javax.xml.transform.TransformerFactory";
+ public static final String XSLT_TRANSFORMER_FACTORY_KEY = "javax.xml.transform.TransformerFactory";
- private static final String XSLT_TRANSFORMER_FACTORY_VALUE = "org.apache.xalan.processor.XSL3TransformerFactoryImpl";
+ public static final String XSLT_TRANSFORMER_FACTORY_VALUE = "org.apache.xalan.processor.XSL3TransformerFactoryImpl";
- private static final String STYLESHEET_LOCATION = "stylesheet-location";
+ public static final String STYLESHEET_LOCATION = "stylesheet-location";
- private static final String STYLESHEET_NODE = "stylesheet-node";
+ public static final String STYLESHEET_NODE = "stylesheet-node";
- private static final String STYLESHEET_TEXT = "stylesheet-text";
+ public static final String STYLESHEET_TEXT = "stylesheet-text";
- private static final String SOURCE_NODE = "source-node";
+ public static final String SOURCE_NODE = "source-node";
- private static final String BASE_OUTPUT_URI = "base-output-uri";
+ public static final String BASE_OUTPUT_URI = "base-output-uri";
- private static final String DELIVERY_FORMAT = "delivery-format";
+ public static final String DELIVERY_FORMAT = "delivery-format";
- private static final String SERLIALIZATION_PARAMS = "serialization-params";
+ public static final String SERLIALIZATION_PARAMS = "serialization-params";
- private static final String DOCUMENT = "document";
+ public static final String DOCUMENT = "document";
- private static final String SERIALIZED = "serialized";
+ public static final String SERIALIZED = "serialized";
- private static final String RAW = "raw";
+ public static final String RAW = "raw";
+
+ public static final String OUTPUT = "output";
- private static final String OUTPUT = "output";
/**
* Execute the function. The function must return a valid object.
@@ -112,6 +114,9 @@ public class FuncTransform extends FunctionDef1Arg
Expression arg0 = m_arg0;
XObject arg0Obj = arg0.execute(xctxt);
+ // Reference of result object instance of, function fn:transform's evaluation.
+ ElemResultDocument.m_fnTransformResult = result;
+
System.setProperty(Constants.XML_DOCUMENT_BUILDER_FACTORY_KEY, Constants.XML_DOCUMENT_BUILDER_FACTORY_VALUE);
System.setProperty(XSLT_TRANSFORMER_FACTORY_KEY, XSLT_TRANSFORMER_FACTORY_VALUE);
@@ -155,17 +160,19 @@ public class FuncTransform extends FunctionDef1Arg
+ "stylesheet document, that will transform an XML input document source.", srcLocator);
}
- // The following optional, function fn:transform's 'map' argument entry
- // keys (along, with corresponding map entry values as well).
+ // The following are optional, function fn:transform's 'map' argument entry
+ // key values.
XObject baseOutputUri = mapArg.get(new XSString(BASE_OUTPUT_URI));
XObject deliveryFormat = mapArg.get(new XSString(DELIVERY_FORMAT));
XObject serializationParams = mapArg.get(new XSString(SERLIALIZATION_PARAMS)); // TO DO
String baseOutputUriStrValue = ((baseOutputUri != null) ? XslTransformEvaluationHelper.getStrVal(
baseOutputUri) : null);
+
if (baseOutputUriStrValue != null) {
URL baseOutputUrl = getAbsoluteUrlValue(baseOutputUriStrValue, srcLocator);
- baseOutputUriStrValue = baseOutputUrl.toString();
+
+ ElemResultDocument.m_BaseOutputUriStrAbsValue = baseOutputUrl.toString();
}
String deliverFormatStrValue = ((deliveryFormat != null) ? XslTransformEvaluationHelper.getStrVal(
@@ -174,11 +181,13 @@ public class FuncTransform extends FunctionDef1Arg
if (!(DOCUMENT.equals(deliverFormatStrValue) || SERIALIZED.equals(deliverFormatStrValue) ||
RAW.equals(deliverFormatStrValue))) {
throw new javax.xml.transform.TransformerException("FODC0005 : An XPath function fn:transform map argument "
- + "entry with key \"delivery-format\" can have value either "
- + "'document', 'serialized' or 'raw'.", srcLocator);
+ + "entry with key \"delivery-format\" can have value either "
+ + "'document', 'serialized' or 'raw'.", srcLocator);
}
}
+ ElemResultDocument.m_fnTransformDeliveryFormat = deliverFormatStrValue;
+
if (xslStylesheetLocObj != null) {
// XPath function fn:transform's XSL transformation, using XSL stylesheet
// information provided by fn:transform's map key 'stylesheet-location'.
@@ -207,7 +216,7 @@ public class FuncTransform extends FunctionDef1Arg
TransformerFactory xslTransformerFactory = TransformerFactory.newInstance();
Transformer transformer = xslTransformerFactory.newTransformer(new StreamSource(xslStylesheetUrlStr));
- DOMResult domResult = new DOMResult();
+ DOMResult domResult = new DOMResult();
transformer.transform(new DOMSource(document), domResult);
DTMManager dtmManager = xctxt.getDTMManager();
@@ -266,7 +275,7 @@ public class FuncTransform extends FunctionDef1Arg
TransformerFactory xslTransformerFactory = TransformerFactory.newInstance();
Transformer transformer = xslTransformerFactory.newTransformer(new DOMSource(xslDocNode));
- DOMResult domResult = new DOMResult();
+ DOMResult domResult = new DOMResult();
transformer.transform(new DOMSource(xmlInpDocNode), domResult);
DTMManager dtmManager = xctxt.getDTMManager();
@@ -367,6 +376,8 @@ public class FuncTransform extends FunctionDef1Arg
}
}
}
+
+ ElemResultDocument.m_BaseOutputUriStrAbsValue = null;
return result;
}
diff --git a/src/main/java/org/apache/xpath/objects/XMLNodeCursorImpl.java b/src/main/java/org/apache/xpath/objects/XMLNodeCursorImpl.java
index 1861977f4..8432d736a 100644
--- a/src/main/java/org/apache/xpath/objects/XMLNodeCursorImpl.java
+++ b/src/main/java/org/apache/xpath/objects/XMLNodeCursorImpl.java
@@ -82,6 +82,13 @@ public class XMLNodeCursorImpl extends NodeCursor
* validating this xdm node object.
*/
private String m_validation = null;
+
+ /**
+ * Class field that supports XPath function fn:transform evaluation,
+ * that invokes an XSL secondary stylesheet having one or more
+ * xsl:result-document instructions.
+ */
+ private DTM m_dtm = null;
/**
* Construct a XMLNodeCursorImpl object.
@@ -1003,6 +1010,14 @@ public class XMLNodeCursorImpl extends NodeCursor
public String getValidationAttrForValidation() {
return m_validation;
}
+
+ public DTM getDtm() {
+ return m_dtm;
+ }
+
+ public void setDtm(DTM dtm) {
+ this.m_dtm = dtm;
+ }
}
diff --git a/src/test/java/org/apache/xalan/tests/xpath3/FnTransformTests.java b/src/test/java/org/apache/xalan/tests/xpath3/FnTransformTests.java
index 8e4601da5..20faa4e7d 100644
--- a/src/test/java/org/apache/xalan/tests/xpath3/FnTransformTests.java
+++ b/src/test/java/org/apache/xalan/tests/xpath3/FnTransformTests.java
@@ -136,5 +136,15 @@ public class FnTransformTests extends XSLTransformTestsUtil {
runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
}
+
+ @Test
+ public void xslFnTransformTest10() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test10.xsl";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test10.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test10.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
}
diff --git a/src/test/resources/fn_transform/gold/test10.out b/src/test/resources/fn_transform/gold/test10.out
new file mode 100644
index 000000000..953e8d733
--- /dev/null
+++ b/src/test/resources/fn_transform/gold/test10.out
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <doc resultOuputRelativeUri="result1.xml">
+ <result1>
+ <a>1</a>
+ <b>2</b>
+ <c>3</c>
+</result1>
+ </doc>
+ <doc resultOuputRelativeUri="result2.xml">
+ <result2>
+ <d>4</d>
+ <e>5</e>
+ <f>6</f>
+ <g>7</g>
+</result2>
+ </doc>
+ <doc resultOuputRelativeUri="trfout"/>
+</result>
diff --git a/src/test/resources/fn_transform/render.xsl b/src/test/resources/fn_transform/render.xsl
index 93625c84d..d9bd2884a 100644
--- a/src/test/resources/fn_transform/render.xsl
+++ b/src/test/resources/fn_transform/render.xsl
@@ -1,6 +1,11 @@
<?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 XSL stylesheet that serves as, secondary stylesheet for XPath
+ function fn:transform. -->
<xsl:output method="xml" indent="yes"/>
@@ -13,6 +18,24 @@
</xsl:for-each>
</details>
</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/src/test/resources/fn_transform/render2.xsl b/src/test/resources/fn_transform/render2.xsl
new file mode 100644
index 000000000..820c762f4
--- /dev/null
+++ b/src/test/resources/fn_transform/render2.xsl
@@ -0,0 +1,52 @@
+<?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 XSL stylesheet that serves as, secondary stylesheet for XPath
+ function fn:transform. -->
+
+ <xsl:output method="xml" omit-xml-declaration="yes"/>
+
+ <xsl:template match="/info">
+ <xsl:result-document href="result1.xml" method="xml">
+ <result1>
+ <xsl:for-each select="*[position() lt 4]">
+ <xsl:element name="{name()}">
+ <xsl:value-of select="position()"/>
+ </xsl:element>
+ </xsl:for-each>
+ </result1>
+ </xsl:result-document>
+ <xsl:result-document href="result2.xml" method="xml">
+ <result2>
+ <xsl:for-each select="*[position() ge 4]">
+ <xsl:element name="{name()}">
+ <xsl:value-of select="position() + 3"/>
+ </xsl:element>
+ </xsl:for-each>
+ </result2>
+ </xsl:result-document>
+ </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/src/test/resources/fn_transform/test10.xsl b/src/test/resources/fn_transform/test10.xsl
new file mode 100644
index 000000000..daea79285
--- /dev/null
+++ b/src/test/resources/fn_transform/test10.xsl
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:map="http://www.w3.org/2005/xpath-functions/map"
+ exclude-result-prefixes="xs map"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- An XSL stylesheet test case, to test XPath 3.1 function fn:transform.
+
+ This stylesheet test case, tests XSL transformation using a secondary
+ stylesheet (render2.xsl in this example) that has xsl:result-document
+ instruction. An xsl:result-document instruction's result output
+ produced via this way, are accumulated within function fn:transform's
+ XDM result map.
+ -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <result>
+ <xsl:variable name="result" select="transform(
+ map {
+ 'stylesheet-location' : 'render2.xsl',
+ 'source-node' : doc('test1.xml'),
+ 'base-output-uri' : 'trfout',
+ 'delivery-format' : 'document'
+ })" as="map(*)"/>
+ <xsl:for-each select="sort(map:keys($result))">
+ <xsl:choose>
+ <xsl:when test="contains(., '/')">
+ <xsl:variable name="urlParts" select="tokenize(xs:string(.), '/')" as="xs:string*"/>
+ <xsl:variable name="urlSuffixStr" select="$urlParts[count($urlParts)]" as="xs:string"/>
+ <doc resultOuputRelativeUri="{$urlSuffixStr}">
+ <xsl:copy-of select="$result(.)"/>
+ </doc>
+ </xsl:when>
+ <xsl:otherwise>
+ <doc resultOuputRelativeUri="{.}">
+ <xsl:copy-of select="$result(.)"/>
+ </doc>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </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
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xalan.apache.org
For additional commands, e-mail: commits-help@xalan.apache.org