Skip to content

Commit f2bddb9

Browse files
committed
fn:transform - convert XPath error from Saxon call
Initial attempt at returning a correct error code per fn:transform specification and consistent with error codes returned by the Saxon transformer which is used internally. Figure out if an an XPathException from Saxon (a saxon class) or an eXist XPathException was a cause of an exception in Saxon invocation. Return a directly wrapped eXist XPathException as the cause of a new eXist XPathException. Return a wrapped Saxon XPathException as the cause of a new eXist XPathException. Generate/convert/wrap into an appropriate eXist XPathException.
1 parent dee3f24 commit f2bddb9

File tree

3 files changed

+99
-10
lines changed

3 files changed

+99
-10
lines changed

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

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import net.sf.saxon.Configuration;
3232
import net.sf.saxon.expr.parser.RetainedStaticContext;
3333
import net.sf.saxon.functions.SystemProperty;
34+
import net.sf.saxon.om.StructuredQName;
3435
import net.sf.saxon.s9api.*;
3536
import net.sf.saxon.serialize.SerializationProperties;
3637
import net.sf.saxon.trans.UncheckedXPathException;
@@ -177,23 +178,53 @@ private XsltExecutable compileExecutable(final Options options) throws XPathExce
177178
FnTransform.ERROR_LISTENER.clear();
178179
return xsltCompiler.compile(options.xsltSource._2); // .compilePackage //TODO(AR) need to implement support for xslt-packages
179180
} catch (final SaxonApiException e) {
180-
Throwable cause = e.getCause();
181-
while (cause != null) {
182-
if (cause instanceof XPathException) {
183-
//Generated by us, possibly in URI resolution, above - throw it directly
184-
throw (XPathException) cause;
185-
}
186-
cause = cause.getCause();
187-
}
181+
//Generated by us, possibly in URI resolution, above - throw it directly
182+
throwOriginalXPathException(e, ErrorCodes.FOXT0003);
188183
final Optional<TransformerException> compilerException = FnTransform.ERROR_LISTENER.getWorst();
189184
if (compilerException.isPresent()) {
190-
throw new XPathException(this, ErrorCodes.FOXT0003,compilerException.get());
185+
throwOriginalXPathException(compilerException.get(), ErrorCodes.FOXT0003);
186+
throw new XPathException(this, ErrorCodes.FOXT0003, compilerException.get());
191187
}
192188
//Wrap any other error
193189
throw new XPathException(this, ErrorCodes.FOXT0003, e.getMessage());
194190
}
195191
}
196192

193+
/**
194+
* Search for an XPathException in the cause chain, and return it "directly"
195+
* Either an eXist XPathException, which is immediate
196+
* Or a Saxon XPathException, when we convert it to something similar in eXist.
197+
*
198+
* @param e the top of the exception stack
199+
* @param defaultErrorCode use this code and its description to fill in blanks in what we finally throw
200+
* @throws XPathException the eventual eXist exception we may throw
201+
*/
202+
private void throwOriginalXPathException(final Throwable e, final ErrorCodes.ErrorCode defaultErrorCode) throws XPathException {
203+
Throwable cause = e;
204+
while (cause != null) {
205+
if (cause instanceof XPathException) {
206+
throw (XPathException) cause;
207+
}
208+
cause = cause.getCause();
209+
}
210+
211+
cause = e;
212+
while (cause != null) {
213+
if (cause instanceof net.sf.saxon.trans.XPathException) {
214+
final net.sf.saxon.trans.XPathException xPathException = (net.sf.saxon.trans.XPathException)cause;
215+
final StructuredQName from = xPathException.getErrorCodeQName();
216+
if (from != null) {
217+
final QName errorCodeQName = new QName(from.getLocalPart(), from.getURI(), from.getPrefix());
218+
final ErrorCodes.ErrorCode errorCode = new ErrorCodes.ErrorCode(errorCodeQName, defaultErrorCode.getDescription());
219+
throw new XPathException(errorCode, cause.getMessage());
220+
} else {
221+
throw new XPathException(this, defaultErrorCode, cause.getMessage());
222+
}
223+
}
224+
cause = cause.getCause();
225+
}
226+
}
227+
197228
/**
198229
* Hash on the options used to create a compiled executable
199230
* Hash should match only when the executable can be re-used.

exist-core/src/test/java/xquery/xquery3/XQuery3Tests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
@RunWith(XSuite.class)
2828
@XSuite.XSuiteFiles({
2929
//"src/test/xquery/xquery3",
30-
"src/test/xquery/xquery3/fnTransform74.xqm"
30+
"src/test/xquery/xquery3/fnTransformErr9.xqm"
3131
})
3232
public class XQuery3Tests {
3333
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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+
xquery version "3.1";
23+
24+
module namespace testTransform="http://exist-db.org/xquery/test/function_transform";
25+
26+
declare namespace test="http://exist-db.org/xquery/xqsuite";
27+
28+
declare variable $testTransform:transform-71-xsl := document {
29+
<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
30+
xmlns:xs='http://www.w3.org/2001/XMLSchema'
31+
xmlns:chrono='http://chronology.com/' version='2.0'>
32+
<xsl:import-schema>
33+
<xs:schema targetNamespace='http://chronology.com/'>
34+
<xs:simpleType name='c4'>
35+
<xs:restriction base='xs:string'>
36+
<xs:pattern value='....'/>
37+
</xs:restriction>
38+
</xs:simpleType>
39+
</xs:schema>
40+
</xsl:import-schema>
41+
<xsl:template name='main'>
42+
<out><xsl:value-of select="chrono:c4('abcd')"/></out>
43+
</xsl:template>
44+
</xsl:stylesheet> };
45+
46+
declare
47+
%test:assertError("XTSE1650")
48+
function testTransform:transform-71() {
49+
let $xsl := $testTransform:transform-71-xsl
50+
let $result := fn:transform(map{
51+
"stylesheet-node":$xsl,
52+
"source-node": parse-xml($xsl),
53+
"initial-template": fn:QName('','main'),
54+
"delivery-format" : "serialized",
55+
"requested-properties" : map{fn:QName('http://www.w3.org/1999/XSL/Transform','is-schema-aware'):false()}
56+
})
57+
return $result("output")
58+
};

0 commit comments

Comments
 (0)