Skip to content

Commit 8f6b9c4

Browse files
authored
Merge pull request #4386 from evolvedbinary/feature/fn-transform
Implement fn:transform
2 parents c66361b + 720a2cb commit 8f6b9c4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+3957
-71
lines changed

exist-core/src/main/java/org/exist/storage/DBBroker.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,12 @@ public void pushSubject(final Subject subject) {
179179
if(LOG.isTraceEnabled()) {
180180
subjectChangeTrace.add(TraceableSubjectChange.push(subject, getId()));
181181
}
182-
this.subject.addFirst(subject);
182+
if (subject == null) {
183+
//TODO (AP) this is a workaround - what is the root cause ?
184+
LOG.warn("Attempt to push null subject ignored.");
185+
} else {
186+
this.subject.addFirst(subject);
187+
}
183188
}
184189

185190
/**

exist-core/src/main/java/org/exist/xquery/ErrorCodes.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,13 @@ public class ErrorCodes {
227227
public static final ErrorCode FOQM0005 = new W3CErrorCode("FOQM0005", "Parameter for dynamically-loaded XQuery " +
228228
"module has incorrect type");
229229
public static final ErrorCode FOQM0006 = new W3CErrorCode("FOQM0006", "No suitable XQuery processor available.");
230+
public static final ErrorCode FOXT0001 = new W3CErrorCode("FOXT0001", "No suitable XSLT processor available.");
231+
public static final ErrorCode FOXT0002 = new W3CErrorCode("FOXT0002", "Invalid parameters to XSLT transformation");
232+
public static final ErrorCode FOXT0003 = new W3CErrorCode("FOXT0003", "XSLT transformation failed");
233+
public static final ErrorCode FOXT0004 = new W3CErrorCode("FOXT0004", "XSLT transformation has been disabled");
234+
public static final ErrorCode FOXT0006 = new W3CErrorCode("FOXT0006", "XSLT output contains non-accepted characters");
235+
236+
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.");
230237

231238
/* eXist specific XQuery and XPath errors
232239
*

exist-core/src/main/java/org/exist/xquery/XQueryContext.java

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3453,4 +3453,109 @@ public HttpContext setSession(final SessionWrapper newSession) {
34533453
return new HttpContext(request, response, newSession);
34543454
}
34553455
}
3456+
3457+
@Override public String toString() {
3458+
return getStringValue();
3459+
}
3460+
3461+
public String getStringValue() {
3462+
final StringBuilder sb = new StringBuilder();
3463+
sb.append('{');
3464+
3465+
sb.append("dynamicDocuments: {");
3466+
if (dynamicDocuments != null) {
3467+
for (final String key : dynamicDocuments.keySet()) {
3468+
sb.append(key).append("-> ");
3469+
sb.append(dynamicDocuments.get(key));
3470+
}
3471+
}
3472+
sb.append('}');
3473+
sb.append('\n');
3474+
3475+
sb.append("dynamicTextResources: {");
3476+
if (dynamicTextResources != null) {
3477+
for (final Map.Entry<Tuple2<String, Charset>, QuadFunctionE<DBBroker, Txn, String, Charset, Reader, XPathException>> entry : dynamicTextResources.entrySet()) {
3478+
sb.append(entry.getKey()).append("-> ").append(entry.getValue());
3479+
}
3480+
}
3481+
sb.append('}');
3482+
sb.append('\n');
3483+
3484+
sb.append("dynamicCollections: {");
3485+
if (dynamicCollections != null) {
3486+
for (final Map.Entry<String,
3487+
TriFunctionE<DBBroker, Txn, String, Sequence, XPathException>> entry : dynamicCollections.entrySet()) {
3488+
sb.append(entry.getKey()).append("-> ").append(entry.getValue());
3489+
}
3490+
}
3491+
sb.append('}');
3492+
sb.append('\n');
3493+
3494+
sb.append("baseURI: ");
3495+
try {
3496+
sb.append(getBaseURI()).append('\n');
3497+
} catch (final XPathException e) {
3498+
sb.append("?");
3499+
}
3500+
3501+
sb.append("inScopePrefixes: {");
3502+
if (inScopePrefixes != null) {
3503+
for (final Map.Entry<String, String> entry : inScopePrefixes.entrySet()) {
3504+
sb.append(entry.getKey()).append("-> ").append(entry.getValue());
3505+
}
3506+
}
3507+
sb.append('}');
3508+
sb.append('\n');
3509+
3510+
sb.append("inScopeNamespaces: {");
3511+
if (inScopeNamespaces != null) {
3512+
for (final Map.Entry<String, String> entry : inScopeNamespaces.entrySet()) {
3513+
sb.append(entry.getKey()).append("-> ").append(entry.getValue());
3514+
}
3515+
}
3516+
sb.append('}');
3517+
sb.append('\n');
3518+
3519+
sb.append("modules: {");
3520+
if (modules != null) {
3521+
for (final Map.Entry<String, Module[]> entry : modules.entrySet()) {
3522+
sb.append(entry.getKey()).append("-> ");
3523+
for (final Module module : modules.get(entry.getKey())) {
3524+
sb.append("namespaceURI: ").append(module.getNamespaceURI()).append('\n');
3525+
sb.append("defaultPrefix: ").append(module.getDefaultPrefix()).append('\n');
3526+
sb.append("description: ").append(module.getDescription()).append('\n');
3527+
for (final Iterator<QName> it = module.getGlobalVariables(); it.hasNext(); ) {
3528+
final QName qName = it.next();
3529+
sb.append(qName).append(';');
3530+
}
3531+
}
3532+
}
3533+
}
3534+
sb.append('}');
3535+
sb.append('\n');
3536+
3537+
sb.append("allModules: {");
3538+
if (allModules != null) {
3539+
for (final Map.Entry<String, Module[]> entry : allModules.entrySet()) {
3540+
sb.append(entry.getKey()).append("-> ");
3541+
for (final Module module : allModules.get(entry.getKey())) {
3542+
sb.append("namespaceURI: ").append(module.getNamespaceURI()).append('\n');
3543+
sb.append("defaultPrefix: ").append(module.getDefaultPrefix()).append('\n');
3544+
sb.append("description: ").append(module.getDescription()).append('\n');
3545+
for (final Iterator<QName> it = module.getGlobalVariables(); it.hasNext(); ) {
3546+
final QName qName = it.next();
3547+
sb.append(qName).append(';');
3548+
}
3549+
}
3550+
}
3551+
}
3552+
sb.append('}');
3553+
sb.append('\n');
3554+
3555+
sb.append('}');
3556+
3557+
return sb.toString();
3558+
}
3559+
3560+
34563561
}

exist-core/src/main/java/org/exist/xquery/functions/fn/FnModule.java

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ public class FnModule extends AbstractInternalModule {
218218
new FunctionDef(FunTokenize.FS_TOKENIZE[2], FunTokenize.class),
219219
new FunctionDef(FunTrace.FS_TRACE1, FunTrace.class),
220220
new FunctionDef(FunTrace.FS_TRACE2, FunTrace.class),
221+
new FunctionDef(FnTransform.FS_TRANSFORM, FnTransform.class),
221222
new FunctionDef(FunTranslate.signature, FunTranslate.class),
222223
new FunctionDef(FunTrueOrFalse.fnTrue, FunTrueOrFalse.class),
223224
new FunctionDef(FunTrueOrFalse.fnFalse, FunTrueOrFalse.class),
@@ -285,37 +286,35 @@ public FnModule(Map<String, List<?>> parameters) {
285286
super(functions, parameters, true);
286287
}
287288

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

295-
/* (non-Javadoc)
296-
* @see org.exist.xquery.Module#getNamespaceURI()
297-
*/
294+
@Override
298295
public String getNamespaceURI() {
299296
return Function.BUILTIN_FUNCTION_NS;
300297
}
301298

302-
/* (non-Javadoc)
303-
* @see org.exist.xquery.Module#getDefaultPrefix()
304-
*/
299+
@Override
305300
public String getDefaultPrefix() {
306301
return PREFIX;
307302
}
308303

304+
@Override
309305
public String getReleaseVersion() {
310306
return RELEASED_IN_VERSION;
311307
}
312308

313-
static FunctionSignature functionSignature(final String name, final String description, final FunctionReturnSequenceType returnType, final FunctionParameterSequenceType... paramTypes) {
314-
return FunctionDSL.functionSignature(new QName(name, Function.BUILTIN_FUNCTION_NS), description, returnType, paramTypes);
309+
static FunctionSignature functionSignature(final String name, final String description,
310+
final FunctionReturnSequenceType returnType, final FunctionParameterSequenceType... paramTypes) {
311+
return FunctionDSL.functionSignature(new QName(name, Function.BUILTIN_FUNCTION_NS), description,
312+
returnType, paramTypes);
315313
}
316314

317-
static FunctionSignature[] functionSignatures(final String name, final String description, final FunctionReturnSequenceType returnType, final FunctionParameterSequenceType[][] variableParamTypes) {
318-
return FunctionDSL.functionSignatures(new QName(name, Function.BUILTIN_FUNCTION_NS), description, returnType, variableParamTypes);
315+
static FunctionSignature[] functionSignatures(final String name, final String description,
316+
final FunctionReturnSequenceType returnType, final FunctionParameterSequenceType[][] variableParamTypes) {
317+
return FunctionDSL.functionSignatures(new QName(name, Function.BUILTIN_FUNCTION_NS), description,
318+
returnType, variableParamTypes);
319319
}
320-
321320
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* eXist-db Open Source Native XML Database
3+
* Copyright (C) 2001 The eXist-db Authors
4+
*
5+
6+
* http://www.exist-db.org
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; either
11+
* version 2.1 of the License, or (at your option) any later version.
12+
*
13+
* This library is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
* Lesser General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Lesser General Public
19+
* License along with this library; if not, write to the Free Software
20+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
*/
22+
23+
package org.exist.xquery.functions.fn;
24+
25+
import org.exist.xquery.BasicFunction;
26+
import org.exist.xquery.FunctionSignature;
27+
import org.exist.xquery.XPathException;
28+
import org.exist.xquery.XQueryContext;
29+
import org.exist.xquery.functions.fn.transform.Transform;
30+
import org.exist.xquery.value.Sequence;
31+
import org.exist.xquery.value.Type;
32+
33+
import static org.exist.xquery.FunctionDSL.param;
34+
import static org.exist.xquery.FunctionDSL.returnsOptMany;
35+
import static org.exist.xquery.functions.fn.FnModule.functionSignature;
36+
37+
/**
38+
* Implementation of fn:transform.
39+
*
40+
* @author <a href="mailto:[email protected]">Adam Retter</a>
41+
* @author <a href="mailto:[email protected]">Alan Paxton</a>
42+
*/
43+
public class FnTransform extends BasicFunction {
44+
45+
private static final String FS_TRANSFORM_NAME = "transform";
46+
static final FunctionSignature FS_TRANSFORM = functionSignature(
47+
FnTransform.FS_TRANSFORM_NAME,
48+
"Invokes a transformation using a dynamically-loaded XSLT stylesheet.",
49+
returnsOptMany(Type.MAP, "The result of the transformation is returned as a map. " +
50+
"There is one entry in the map for the principal result document, and one for each " +
51+
"secondary result document. The key is a URI in the form of an xs:string value. " +
52+
"The key for the principal result document is the base output URI if specified, or " +
53+
"the string \"output\" otherwise. The key for secondary result documents is the URI of the " +
54+
"document, as an absolute URI. The associated value in each entry depends on the requested " +
55+
"delivery format. If the delivery format is document, the value is a document node. If the " +
56+
"delivery format is serialized, the value is a string containing the serialized result."),
57+
param("options", Type.MAP, "The inputs to the transformation are supplied in the form of a map")
58+
);
59+
60+
private Transform transform = new Transform(context, this);
61+
62+
public FnTransform(final XQueryContext context, final FunctionSignature signature) {
63+
super(context, signature);
64+
}
65+
66+
@Override
67+
public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException {
68+
return transform.eval(args, contextSequence);
69+
}
70+
}

0 commit comments

Comments
 (0)