Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement fn:transform #4386

Merged
merged 72 commits into from
Aug 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
54b3037
[feature] Implementation of fn:transform
adamretter May 12, 2022
640cf41
[ignore] Code cleanup
adamretter May 12, 2022
c4b2d31
[feature] fn-transform - first functionality
alanpaxton May 16, 2022
e773003
fn:transform - set to run all unit tests again
alanpaxton May 26, 2022
b36a2e9
fn:transform - fix cut-n-paste option name error
alanpaxton May 26, 2022
3c880a9
fn:transform - use DocUtils to get stylesheet
alanpaxton May 30, 2022
2e71b6c
fn:transform - get xsl:version from simplified stylesheet
alanpaxton May 31, 2022
340e878
fn:transform - base URI for transformation
alanpaxton Jun 1, 2022
edeb1b7
fn:transform - refactor options, handle raw output
alanpaxton Jun 11, 2022
564fd66
fn:transform - work round a broker crash.
alanpaxton Jun 11, 2022
94d8bfa
fn:transform - Escape quotes in conversion
alanpaxton Jun 15, 2022
713e39d
fn:transform - Fix multiple document output
alanpaxton Jun 15, 2022
9558366
add initial-function param to fn:transform
alanpaxton Jun 15, 2022
38f209b
fn:transform - remove wrong “raw” < 3.0
alanpaxton Jun 15, 2022
f00c0e7
fn:transform - Handle some XdmValue conversions
alanpaxton Jun 21, 2022
f5c3561
fn:transform - transformer parameters
alanpaxton Jun 21, 2022
12df629
fn:transform - initial- mode template conflict
alanpaxton Jun 21, 2022
a6210b4
fn:transform - parameter conflict
alanpaxton Jun 22, 2022
fdb0772
fn:transform - attempt at initial-match-selection
alanpaxton Jun 22, 2022
1dba2da
fn:transform - sequence conversion Saxon to eXist
alanpaxton Jun 22, 2022
71186f9
fn:transform - fix “raw” output on callFunction
alanpaxton Jun 22, 2022
91d9239
fn:transform - initial-match-selection as document
alanpaxton Jun 22, 2022
dd6b0a7
fn:transform - base-output-uri param type
alanpaxton Jun 22, 2022
05c5ae8
fn:transform - string URI convertibility
alanpaxton Jul 7, 2022
6ec173e
fn:transform - add initial-mode test (failing)
alanpaxton Jul 7, 2022
17f1bad
fn:transform - refactor template invocation flow
alanpaxton Jul 7, 2022
b0882ff
fn:transform - pass initial-mode parameter
alanpaxton Jul 11, 2022
f09aa19
fn:transform - global-context-item parameter
alanpaxton Jul 11, 2022
ac9d1fb
fn:transform - type of base output uri
alanpaxton Jul 11, 2022
c075a6a
fn:transform - test stylesheet location, base URI
alanpaxton Jul 12, 2022
214f467
fn:transform - exactly one source of stylesheet
alanpaxton Jul 12, 2022
944d4bc
fn:transform - source-node may not be a document
alanpaxton Jul 13, 2022
b082606
fn:transform - stylesheet-params ignored
alanpaxton Jul 13, 2022
345ef6d
fn:transform - add UT for XQTS fn-transform-err-9
alanpaxton Jul 14, 2022
0c313a1
fn:transform - resolve base URI in stylesheet-text
alanpaxton Jul 14, 2022
7df6f5f
fn:transform - refactor, pull out compilation step
alanpaxton Jul 14, 2022
7bf576c
Include path to source node in compiled checksum
alanpaxton Jul 14, 2022
d22ccf0
Remove redundant use of context base URI
alanpaxton Jul 15, 2022
d5d0e3f
fn:transform - resolvedStylesheetBaseURI optional
alanpaxton Jul 15, 2022
ac9fc2a
[bugfix] fn:transform - correct URI error codes
alanpaxton Jul 15, 2022
f091597
[bugfix] fn:transform initial-function param
alanpaxton Jul 15, 2022
e222e3b
[bugfix] fn:transform - relative stylesheet
alanpaxton Jul 15, 2022
c7008d9
[bugfix] fn:transform - global-context-item
alanpaxton Jul 19, 2022
7d94522
[testsuite] fn:transform - fn-transform-82e UT
alanpaxton Jul 19, 2022
706a52f
[testsuite] fn:transform - repair UTs
alanpaxton Aug 3, 2022
0e34613
[bugfix] fn:transform - cache key was too liberal.
alanpaxton Jul 20, 2022
5cc67f5
Remove debugging code
alanpaxton Jul 21, 2022
1cc159a
[feature] fn-transform “serialization-params”
alanpaxton Jul 26, 2022
a563087
[feature] fn:transform - XSLT compilation errors
alanpaxton Jul 28, 2022
74402d9
[testsuite] fn:transform UT for XQTS transform-68
alanpaxton Jul 28, 2022
20dc1f1
[feature] fn:transform - requested-properties
alanpaxton Jul 28, 2022
dee3f24
[testsuite] fn:transform UT requested-properties
alanpaxton Jul 28, 2022
f2bddb9
fn:transform - convert XPath error from Saxon call
alanpaxton Aug 1, 2022
0702a6e
[feature] fn:transform post-process function
alanpaxton Aug 1, 2022
8fb3281
[bugfix] fn:transform RAW destination for results
alanpaxton Aug 2, 2022
9ce9b10
fn:transform - simplify path to invoke transformer
alanpaxton Aug 2, 2022
9543567
fn:transform - fixes to IntelliJ code inspections
alanpaxton Aug 2, 2022
c2d9f54
[bugfix] fn:transform - clean up error handling
alanpaxton Aug 2, 2022
b269542
fn:transform - refactor into own package
alanpaxton Aug 2, 2022
563edbd
fn:transform - tidy up unit tests
alanpaxton Aug 2, 2022
22fef81
[bugfix] fn:transform refactor had multi doc bug
alanpaxton Aug 2, 2022
b09da11
[testsuite] auto fix IntelliJ inspections
alanpaxton Aug 3, 2022
3f41d99
[bugfix] AnyURI should not be string subtype
alanpaxton Aug 3, 2022
067c8b2
[bugfix] fn:transform - sonartype check
alanpaxton Aug 4, 2022
ced4937
fn:transform - remove redundant code
alanpaxton Aug 4, 2022
7647cfc
fn:transform - UTs for increased coverage
alanpaxton Aug 4, 2022
7f58927
fn:transform - resolve TODO as nothing to do
alanpaxton Aug 4, 2022
36e490e
fn:transform - fix inspection warnings
alanpaxton Aug 4, 2022
623615e
fn:transform - code quality fixes
alanpaxton Aug 8, 2022
a27be64
[bugfix] fn:transform - race condition
alanpaxton Aug 8, 2022
339e40d
fn:transform - some sonarcloud observation fixes
alanpaxton Aug 8, 2022
720a2cb
fn:transform - review feedback
alanpaxton Aug 10, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion exist-core/src/main/java/org/exist/storage/DBBroker.java
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,12 @@ public void pushSubject(final Subject subject) {
if(LOG.isTraceEnabled()) {
subjectChangeTrace.add(TraceableSubjectChange.push(subject, getId()));
}
this.subject.addFirst(subject);
if (subject == null) {
//TODO (AP) this is a workaround - what is the root cause ?
LOG.warn("Attempt to push null subject ignored.");
} else {
this.subject.addFirst(subject);
}
}

/**
Expand Down
7 changes: 7 additions & 0 deletions exist-core/src/main/java/org/exist/xquery/ErrorCodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,13 @@ public class ErrorCodes {
public static final ErrorCode FOQM0005 = new W3CErrorCode("FOQM0005", "Parameter for dynamically-loaded XQuery " +
"module has incorrect type");
public static final ErrorCode FOQM0006 = new W3CErrorCode("FOQM0006", "No suitable XQuery processor available.");
public static final ErrorCode FOXT0001 = new W3CErrorCode("FOXT0001", "No suitable XSLT processor available.");
public static final ErrorCode FOXT0002 = new W3CErrorCode("FOXT0002", "Invalid parameters to XSLT transformation");
public static final ErrorCode FOXT0003 = new W3CErrorCode("FOXT0003", "XSLT transformation failed");
public static final ErrorCode FOXT0004 = new W3CErrorCode("FOXT0004", "XSLT transformation has been disabled");
public static final ErrorCode FOXT0006 = new W3CErrorCode("FOXT0006", "XSLT output contains non-accepted characters");

public static final ErrorCode XTSE0165 = new W3CErrorCode("XTSE0165","It is a static error if the processor is not able to retrieve the resource identified by the URI reference [ in the href attribute of xsl:include or xsl:import] , or if the resource that is retrieved does not contain a stylesheet module conforming to this specification.");

/* eXist specific XQuery and XPath errors
*
Expand Down
105 changes: 105 additions & 0 deletions exist-core/src/main/java/org/exist/xquery/XQueryContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -3445,4 +3445,109 @@ public HttpContext setSession(final SessionWrapper newSession) {
return new HttpContext(request, response, newSession);
}
}

@Override public String toString() {
return getStringValue();
}

public String getStringValue() {
dizzzz marked this conversation as resolved.
Show resolved Hide resolved
final StringBuilder sb = new StringBuilder();
sb.append('{');

sb.append("dynamicDocuments: {");
if (dynamicDocuments != null) {
for (final String key : dynamicDocuments.keySet()) {
sb.append(key).append("-> ");
sb.append(dynamicDocuments.get(key));
}
}
sb.append('}');
sb.append('\n');

sb.append("dynamicTextResources: {");
if (dynamicTextResources != null) {
for (final Map.Entry<Tuple2<String, Charset>, QuadFunctionE<DBBroker, Txn, String, Charset, Reader, XPathException>> entry : dynamicTextResources.entrySet()) {
sb.append(entry.getKey()).append("-> ").append(entry.getValue());
}
}
sb.append('}');
sb.append('\n');

sb.append("dynamicCollections: {");
if (dynamicCollections != null) {
for (final Map.Entry<String,
TriFunctionE<DBBroker, Txn, String, Sequence, XPathException>> entry : dynamicCollections.entrySet()) {
sb.append(entry.getKey()).append("-> ").append(entry.getValue());
}
}
sb.append('}');
sb.append('\n');

sb.append("baseURI: ");
try {
sb.append(getBaseURI()).append('\n');
} catch (final XPathException e) {
sb.append("?");
}

sb.append("inScopePrefixes: {");
if (inScopePrefixes != null) {
for (final Map.Entry<String, String> entry : inScopePrefixes.entrySet()) {
sb.append(entry.getKey()).append("-> ").append(entry.getValue());
}
}
sb.append('}');
sb.append('\n');

sb.append("inScopeNamespaces: {");
if (inScopeNamespaces != null) {
for (final Map.Entry<String, String> entry : inScopeNamespaces.entrySet()) {
sb.append(entry.getKey()).append("-> ").append(entry.getValue());
}
}
sb.append('}');
sb.append('\n');

sb.append("modules: {");
if (modules != null) {
for (final Map.Entry<String, Module[]> entry : modules.entrySet()) {
sb.append(entry.getKey()).append("-> ");
for (final Module module : modules.get(entry.getKey())) {
sb.append("namespaceURI: ").append(module.getNamespaceURI()).append('\n');
sb.append("defaultPrefix: ").append(module.getDefaultPrefix()).append('\n');
sb.append("description: ").append(module.getDescription()).append('\n');
for (final Iterator<QName> it = module.getGlobalVariables(); it.hasNext(); ) {
final QName qName = it.next();
sb.append(qName).append(';');
}
}
}
}
sb.append('}');
sb.append('\n');

sb.append("allModules: {");
if (allModules != null) {
for (final Map.Entry<String, Module[]> entry : allModules.entrySet()) {
sb.append(entry.getKey()).append("-> ");
for (final Module module : allModules.get(entry.getKey())) {
sb.append("namespaceURI: ").append(module.getNamespaceURI()).append('\n');
sb.append("defaultPrefix: ").append(module.getDefaultPrefix()).append('\n');
sb.append("description: ").append(module.getDescription()).append('\n');
for (final Iterator<QName> it = module.getGlobalVariables(); it.hasNext(); ) {
final QName qName = it.next();
sb.append(qName).append(';');
}
}
}
}
sb.append('}');
sb.append('\n');

sb.append('}');

return sb.toString();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ public class FnModule extends AbstractInternalModule {
new FunctionDef(FunTokenize.FS_TOKENIZE[2], FunTokenize.class),
new FunctionDef(FunTrace.FS_TRACE1, FunTrace.class),
new FunctionDef(FunTrace.FS_TRACE2, FunTrace.class),
new FunctionDef(FnTransform.FS_TRANSFORM, FnTransform.class),
new FunctionDef(FunTranslate.signature, FunTranslate.class),
new FunctionDef(FunTrueOrFalse.fnTrue, FunTrueOrFalse.class),
new FunctionDef(FunTrueOrFalse.fnFalse, FunTrueOrFalse.class),
Expand Down Expand Up @@ -280,37 +281,35 @@ public FnModule(Map<String, List<?>> parameters) {
super(functions, parameters, true);
}

/* (non-Javadoc)
* @see org.exist.xquery.Module#getDescription()
*/
@Override
public String getDescription() {
return "A module with the XQuery/XPath Core Library Functions";
}

/* (non-Javadoc)
* @see org.exist.xquery.Module#getNamespaceURI()
*/
@Override
public String getNamespaceURI() {
return Function.BUILTIN_FUNCTION_NS;
}

/* (non-Javadoc)
* @see org.exist.xquery.Module#getDefaultPrefix()
*/
@Override
public String getDefaultPrefix() {
return PREFIX;
}

@Override
public String getReleaseVersion() {
return RELEASED_IN_VERSION;
}

static FunctionSignature functionSignature(final String name, final String description, final FunctionReturnSequenceType returnType, final FunctionParameterSequenceType... paramTypes) {
return FunctionDSL.functionSignature(new QName(name, Function.BUILTIN_FUNCTION_NS), description, returnType, paramTypes);
static FunctionSignature functionSignature(final String name, final String description,
final FunctionReturnSequenceType returnType, final FunctionParameterSequenceType... paramTypes) {
return FunctionDSL.functionSignature(new QName(name, Function.BUILTIN_FUNCTION_NS), description,
returnType, paramTypes);
}

static FunctionSignature[] functionSignatures(final String name, final String description, final FunctionReturnSequenceType returnType, final FunctionParameterSequenceType[][] variableParamTypes) {
return FunctionDSL.functionSignatures(new QName(name, Function.BUILTIN_FUNCTION_NS), description, returnType, variableParamTypes);
static FunctionSignature[] functionSignatures(final String name, final String description,
final FunctionReturnSequenceType returnType, final FunctionParameterSequenceType[][] variableParamTypes) {
return FunctionDSL.functionSignatures(new QName(name, Function.BUILTIN_FUNCTION_NS), description,
returnType, variableParamTypes);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* eXist-db Open Source Native XML Database
* Copyright (C) 2001 The eXist-db Authors
*
* info@exist-db.org
* http://www.exist-db.org
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

package org.exist.xquery.functions.fn;

import org.exist.xquery.BasicFunction;
import org.exist.xquery.FunctionSignature;
import org.exist.xquery.XPathException;
import org.exist.xquery.XQueryContext;
import org.exist.xquery.functions.fn.transform.Transform;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.Type;

import static org.exist.xquery.FunctionDSL.param;
import static org.exist.xquery.FunctionDSL.returnsOptMany;
import static org.exist.xquery.functions.fn.FnModule.functionSignature;

/**
* Implementation of fn:transform.
*
* @author <a href="mailto:adam@evolvedbinary.com">Adam Retter</a>
* @author <a href="mailto:alan@evolvedbinary.com">Alan Paxton</a>
*/
public class FnTransform extends BasicFunction {

private static final String FS_TRANSFORM_NAME = "transform";
static final FunctionSignature FS_TRANSFORM = functionSignature(
FnTransform.FS_TRANSFORM_NAME,
"Invokes a transformation using a dynamically-loaded XSLT stylesheet.",
returnsOptMany(Type.MAP, "The result of the transformation is returned as a map. " +
"There is one entry in the map for the principal result document, and one for each " +
"secondary result document. The key is a URI in the form of an xs:string value. " +
"The key for the principal result document is the base output URI if specified, or " +
"the string \"output\" otherwise. The key for secondary result documents is the URI of the " +
"document, as an absolute URI. The associated value in each entry depends on the requested " +
"delivery format. If the delivery format is document, the value is a document node. If the " +
"delivery format is serialized, the value is a string containing the serialized result."),
param("options", Type.MAP, "The inputs to the transformation are supplied in the form of a map")
);

private Transform transform = new Transform(context, this);

public FnTransform(final XQueryContext context, final FunctionSignature signature) {
super(context, signature);
}

@Override
public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException {
return transform.eval(args, contextSequence);
}
}
Loading