当尝试从EJB上下文中调用XQuery时,我遇到了这个奇怪的问题。当我在Java主上下文中运行此程序时,我没有任何问题-它按计划工作。
但是当我在容器上下文中运行相同的逻辑时,总是会遇到此异常:
net.sf.saxon.s9api.SaxonApiException: No function with name {http://www.w3.org/2005/xquery-local-functions} func and arity 1 has been declared in the query
at net.sf.saxon.s9api.XQueryEvaluator.callFunction(XQueryEvaluator.java:593)
at com.acme.xquery.controller.QueryControl.runQuery(QueryControl.java:76)
at com.acme.kafka.KafkaRecordHandler.run(KafkaRecordHandler.java:25)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: net.sf.saxon.trans.XPathException: No function with name {http://www.w3.org/2005/xquery-local-functions}func and arity 1 has been declared in the query
at net.sf.saxon.s9api.SaxonApiException.<init>(SaxonApiException.java:36)
... 8 more
可以正常工作的简单测试类如下:
import java.io.File;
import java.io.StringReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import net.sf.saxon.s9api.DocumentBuilder;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.XQueryCompiler;
import net.sf.saxon.s9api.XQueryEvaluator;
import net.sf.saxon.s9api.XQueryExecutable;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.s9api.XdmValue;
public class Test {
private static HashMap<String, XQueryExecutable> cache = new HashMap<String, XQueryExecutable>();
Processor saxon = new Processor(false);
XQueryCompiler compiler = saxon.newXQueryCompiler();
public static void main(String[] args) throws Exception {
Test t = new Test();
t.prep();
byte[] bytes = Files.readAllBytes(Paths.get("C:\\dev\\booking.xml"));
String content = new String(bytes);
// transform xml 1000 times
for (int i = 0; i < 1; i++)
t.transform(content);
}
private void prep() throws Exception {
XQueryExecutable exec = compiler.compile(new File("C:\\project\\cbcPrio\\src\\main\\resources\\createBooking.xqy"));
cache.put("TEST", exec);
}
private XQueryExecutable getExpression(String key) {
return cache.get(key);
}
private void transform(String xml ) throws Exception {
XQueryExecutable exec = getExpression("TEST");
XQueryEvaluator query = exec.load();
DocumentBuilder builder = saxon.newDocumentBuilder();
Source src = new StreamSource(new StringReader(xml));
XdmNode doc = builder.build(src);
XdmValue result = query.callFunction(new QName("http://www.w3.org/2005/xquery-local-functions", "func"), new XdmValue[]{doc});
System.out.println( result );
}
}
用作EJB上下文一部分的逻辑(这将引发上面的异常)如下:
import java.io.StringReader;
import java.util.HashMap;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import net.sf.saxon.s9api.DocumentBuilder;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.XQueryCompiler;
import net.sf.saxon.s9api.XQueryEvaluator;
import net.sf.saxon.s9api.XQueryExecutable;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.s9api.XdmValue;
public final class QueryControl {
private enum xqFiles {
CREATEBOOKING("/createBooking.xqy");
private final String fileLocation;
xqFiles(String fileLocation){
this.fileLocation = fileLocation;
}
public String getFileLocation(){
return fileLocation;
}
}
private static HashMap<String, XQueryExecutable > cache = new HashMap<String, XQueryExecutable>();
Processor saxon = new Processor(false);
XQueryCompiler compiler = saxon.newXQueryCompiler();
private static QueryControl qc = null;
private void loadXQCache(String key, String fileLocation) throws Exception {
try {
XQueryExecutable exec = compiler.compile(fileLocation);
cache.put(key, exec);
} catch (Exception e) {
throw new RuntimeException("Problem with loading XQuery files!", e);
}
}
public static QueryControl newInstance() throws Exception {
if (qc == null)
qc = new QueryControl();
return qc;
}
private QueryControl() throws Exception {
loadXQCache(xqFiles.CREATEBOOKING.name(), xqFiles.CREATEBOOKING.getFileLocation());
}
public void stop() {
try {
//this.con.close();
} catch (Exception xe) {
xe.printStackTrace();
}
}
public void runQuery(String xml) throws Exception {
XQueryExecutable exec = getPreparedExpression(xqFiles.CREATEBOOKING.name());
XQueryEvaluator query = exec.load();
DocumentBuilder builder = saxon.newDocumentBuilder();
Source src = new StreamSource(new StringReader(xml));
XdmNode doc = builder.build(src);
XdmValue result = query.callFunction(new QName("http://www.w3.org/2005/xquery-local-functions", "func"), new XdmValue[]{doc});
System.out.println( result );
}
private static XQueryExecutable getPreparedExpression(String key) throws Exception {
return cache.get(key);
}
}
XQuery(xqy)看起来像这样:
xquery version "1.0" encoding "utf-8";
(:: OracleAnnotationVersion "1.0" ::)
declare namespace dtl="http://soa.acme.com/Account/createBooking";
(:: import schema at "../../../../ABC_Booking_V1.0/xsd/DTLModels/createBooking.xsd" ::)
declare variable $ind as document-node() (:: schema-element(dtl:createBookingRequest) ::) external;
declare function local:func($ind as document-node() (:: schema-element(dtl:createBookingRequest) ::) ) as element() (:: schema-element(dtl:createBookingRequest) ::) {
let $createBookingOriginalRequest := $ind/dtl:createBookingRequest
return
<dtl:createBookingRequest>
<dtl:AccountingUnit>{fn:data($createBookingOriginalRequest/dtl:AccountingUnit)}</dtl:AccountingUnit>
<dtl:RequestingApplCode>{fn:data($createBookingOriginalRequest/dtl:RequestingApplCode)}</dtl:RequestingApplCode>
<dtl:DeliveryId>{fn:data($createBookingOriginalRequest/dtl:DeliveryId)}</dtl:DeliveryId>
<dtl:MessageSeqNo>{fn:data($createBookingOriginalRequest/dtl:MessageSeqNo)}</dtl:MessageSeqNo>
<dtl:OrigTimeStamp>{fn:data($createBookingOriginalRequest/dtl:OrigTimeStamp)}</dtl:OrigTimeStamp>
<dtl:TransForcingCode>1</dtl:TransForcingCode>
<dtl:WantResponse>N</dtl:WantResponse>
<dtl:CommLayerTimeStamps>
<dtl:CommLayerTime>
<dtl:CommLayer>TM CR Booking Creation</dtl:CommLayer>
<dtl:CommLayerTimeStamp>{fn:current-dateTime()}</dtl:CommLayerTimeStamp>
</dtl:CommLayerTime>
</dtl:CommLayerTimeStamps>
{
for $request in $createBookingOriginalRequest/dtl:RequestTransactionList
return
<dtl:RequestTransactionList>
<dtl:TransactionSeqNo>{fn:data($request/dtl:TransactionSeqNo)}</dtl:TransactionSeqNo>
<dtl:TransactionType>0002</dtl:TransactionType>
{
if ($request/dtl:ExposureDate)
then <dtl:ExposureDate>{fn:data($request/dtl:ExposureDate)}</dtl:ExposureDate>
else ()
}
{
if ($request/dtl:TradeExecutionDateTime)
then <dtl:TradeExecutionDateTime>{fn:data($request/dtl:TradeExecutionDateTime)}</dtl:TradeExecutionDateTime>
else ()
}
//majority of contents removed due to length restrictions on SO
</dtl:RequestTransactionList>
}
</dtl:createBookingRequest>
};
local:func($ind)
最后是XML(简称):
<v2:createBookingRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://soa.acme.com/Account/createBooking C:\development\acme-Services\integration-services\abc\ABC_Booking_Txx_v1.0\interface\ABC\DTLModels\createBooking_v20.xsd"
xmlns:v2="http://soa.acme.com/Account/createBooking">
<v2:AccountingUnit>1764</v2:AccountingUnit>
<v2:RequestingApplCode>YE</v2:RequestingApplCode>
<v2:DeliveryId>delID1</v2:DeliveryId>
<v2:MessageSeqNo>100003</v2:MessageSeqNo>
<v2:OrigTimeStamp>2018-07-09T13:05:30.738+02:00</v2:OrigTimeStamp>
<v2:TransForcingCode>1</v2:TransForcingCode>
<v2:WantResponse>Y</v2:WantResponse>
<v2:RequestTransactionList>
<v2:TransactionSeqNo>00000001</v2:TransactionSeqNo>
<!-- removed a large part of this file due to length limitation on SO -->
</v2:RequestTransactionList>
</v2:createBookingRequest>