如何在 JBoss eap 6.1 服务器中启用 XSLT 2.0 处理器,以消除 XSLT 2.0 函数不可用等错误

How do I enable XSLT 2.0 processor in JBoss eap 6.1 server, to get rid of errors like XSLT 2.0 functions are not available

我正在尝试在 XSLT 2.0 中设置日期格式。当我尝试在我的工作区中 运行 它时,它 运行 很好并且我得到了正确的响应。但是,当我在 JBoss eap 6.1 上部署我的 jar 后尝试实现相同的目标时,出现以下错误:

16:35:02,311 错误 [XSLTUtil] (DefaultQuartzScheduler-camel-12_Worker-2) XSLTUtil|0|TransformerException:使用 xslt 文件转换 xml 时出错: javax.xml.transform.TransformerException: org.xml.sax.SAXException: 找不到函数: format-dateTime javax.xml.transform.TransformerException: 找不到函数:format-dateTime|

我的 Xsl 文件:我在这里尝试使用 format-dateTime 将当前日期格式化为其他格式。

<?xml version='1.0' encoding='UTF-8'?>
<xsl:stylesheet version='2.0'
    xmlns:xsl='http://www.w3.org/1999/XSL/Transform' 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:func="http://exslt.org/functions" 
    xmlns:date="http://exslt.org/dates-and-times" 
    date:doc="http://www.exslt.org/date" exclude-result-prefixes="date func">

    <xsl:import href="date.xsl"/>
    <xsl:output method="xml" encoding="UTF-8" indent="yes" />
    <xsl:template match="/">
        <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:max="http://www.ibm.com/maximo">
            <soapenv:Header/>
            <soapenv:Body>
                <max:CreateMXINCIDENT_WSTB creationDateTime="" baseLanguage="" transLanguage="" messageID="" maximoVersion="">
                    <max:MXINCIDENT_WSTBSet>
                        <max:MXINCIDENT_WST action="" relationship="" deleteForInsert="" transLanguage="">
                            <max:MAXINTERRORMSG></max:MAXINTERRORMSG>
                            <max:ACTIVITY changed="true">
                                <xsl:value-of select='/tTroubleticket/activity' />
                            </max:ACTIVITY>
                            <max:BLOCK changed="">
                                <xsl:value-of select='/tTroubleticket/block' />
                            </max:BLOCK>
                            <max:CHANGEBY changed="true">AOS</max:CHANGEBY>
                            <max:CHANGEDATE changed="true">
                                <xsl:value-of select="format-dateTime(current-dateTime(), '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01].[f001][Z]')" />
                            </max:CHANGEDATE>
                            <max:CLASS changed="true">INCIDENT</max:CLASS>
                            <max:COMMERRORTYPE changed="true">
                                <xsl:value-of select='/tTroubleticket/commErrorType' />
                            </max:COMMERRORTYPE>
                            <max:COMPONENTLIST changed="true"></max:COMPONENTLIST>
                            <max:CREATEDBY changed=""></max:CREATEDBY>
                            <max:CREATIONDATE changed="true">
                                <xsl:value-of select="/tTroubleticket/interactiondate" />
                                <!-- <xsl:variable name="date" select="/tTroubleticket/interactiondate"></xsl:variable>
                                <xsl:variable name="intDt" select="xs:dateTime(concat(
                                    substring($date, 1, 4),'-',
                                    substring($date, 6, 2),'-',
                                    substring($date, 9, 2),'T',
                                    substring($date, 12, 2),':',
                                    substring($date, 15, 2),':',
                                    substring($date, 18, 2)))"></xsl:variable>
                                <xsl:value-of select="format-dateTime($intDt, '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01].[f001][Z]')" /> -->
                            </max:CREATIONDATE>
                            <max:DESCRIPTION changed="">
                                <xsl:variable name="objOwner" select="/tTroubleticket/mc_object_owner" />
                                <xsl:variable name="mcOwner" select="/tTroubleticket/mc_owner" />
                                <xsl:value-of select="concat($objOwner,'|',$mcOwner)" />
                            </max:DESCRIPTION>
                            </max:MXINCIDENT_WST>
                    </max:MXINCIDENT_WSTBSet>
                </max:CreateMXINCIDENT_WSTB>
            </soapenv:Body>
        </soapenv:Envelope>
    </xsl:template>
</xsl:stylesheet>

这是我用于 transforming/mapping 我的 XML 和 XSL 的 XSLT 实用程序 class 文件。在下面的 java 文件中,我正在从我的本地目录读取 xsl 文件。将 jar 部署到 JBoss 服务器后,我将读取文件位置并将其传递给 XSLTFilename 变量。

package com.al.ddr.fsw.tt.util.xml.transform;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import com.al.ddr.common.logging.jb.Logger;    
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

public class XSLTUtil {

    Logger logger = Logger.getLogger(XSLTUtil.class);
    //Logger logger = Logger.getLogger("XSLTUtil");

    public String transformXML(String inXML, String XSLTFilename) throws TransformerFactoryConfigurationError, TransformerException {
        StringWriter xmlResultResource = new StringWriter();
        try {
            Source xslDoc = new StreamSource(XSLTFilename);
            Transformer transformer = TransformerFactory.newInstance().newTransformer(xslDoc);
            transformer.transform(new StreamSource(new StringReader(inXML)), new StreamResult(xmlResultResource));
            //logger.info("XSLTUtil",0,"XSLTUtil - transformXML() - Result : \n" + xmlResultResource.getBuffer().toString(),"");
        } catch (TransformerException e) {
            //logger.error("XSLTUtil",0,"TransformerException : Error occured while transforming xml with the xslt file : \n"+e.getMessage(),"");
        } catch (Exception e) {
            e.getMessage();
            //logger.error("XSLTUtil",0,"Error occured while transforming xml with the xslt file : \n"+e.getMessage(),"");
        }
        return xmlResultResource.getBuffer().toString();
    }

    public static void main(String[] args) throws TransformerFactoryConfigurationError, TransformerException {

        String xmlSourceResource = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" + "<tTroubleticket>" + "<alarms>" + "<tTroubleTicketAlarm>" + "<alarmid>3117</alarmid>"
                + "<alarmName>OSS</alarmName>" + "</tTroubleTicketAlarm>" + "<tTroubleTicketAlarm>" + "<alarmid>3118</alarmid>" + "<alarmName>OS123</alarmName>" + "</tTroubleTicketAlarm>"
                + "</alarms>" + "<interactiondate>2014-11-21 11:22:34</interactiondate>" + "<troubleticketstate>QUEUED</troubleticketstate>"
                + "<mc_object_owner>amit</mc_object_owner>"+ "<mc_owner>kumar</mc_owner>"
                + "<troubledescription>Server down</troubledescription>" + "<system>IRU</system>" + "<subsystem>FJKH</subsystem>" + "<severity>1</severity>" + "<tecGroup>NSN</tecGroup>"
                + "<block>block</block>" + "<subBlock>sub_block</subBlock>" + "<history>new ticket created</history>" + "<Log>" + "<Logname>FJKH</Logname>" + "<LogSize>Nothing</LogSize>"
                + "<LogFile>" + "Hi" + "</LogFile>" + "</Log>" + "</tTroubleticket>";

        String xsltFilename = "C:/Users/akuma249/TTSimulator/aor-platform-tt/src/config/xslt_COLOMBIA/v11/CreateTicketRequest_WS_11.xsl";

        XSLTUtil util = new XSLTUtil();
        String transformedXML = util.transformXML(xmlSourceResource, xsltFilename);
        System.out.println(transformedXML);

    }

}

这段特殊的代码在我的工作区中运行良好。 我是否需要在我的 JBoss 服务器上配置一些东西才能解决这个问题? 请让我知道我到底缺少什么。

<xsl:value-of select="format-dateTime(current-dateTime(), '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01].[f001][Z]')" /> 行和 <xsl:stylesheet version='2.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:xs="http://www.w3.org/2001/XMLSchema" 行表明您正在尝试使用 XSLT 2.0 dateTime 数据类型及其函数。要使其正常工作,您需要使用像 Saxon 9 这样的 XSLT 2.0 处理器。如果您收到有关未定义此类函数的错误,那么您可能 运行 使用像 Xalan 这样的 XSLT 1.0 处理器的代码。我不熟悉 jboss,所以我无法告诉您如何将其设置为使用 XSLT 2.0 处理器而不是 XSLT 1.0 处理器。

为了覆盖 JBoss EAP 6.1 默认支持的 XALAN 处理器,我们可以添加 JAVA_OPTS="$JAVA_OPTS -Djavax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl"standalone.conf 这会覆盖支持 XSLT 1.0 的 XALAN 处理器和支持 XSLT 2.0 的 SAXON。 谢谢@Martin Honnen给我提示

设置 Java 选项标志

-Djavax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl

在您的应用程序服务器启动脚本中也确实需要普通 JVM 才能访问例如class 路径上的 saxon-8.7.jar 和 saxon-dom-8.7.jar。

但是在这样做时,您所有的 XSL 模板都需要 否则您将得到 "Warning: Running an XSLT 1.0 stylesheet with an XSLT 2.0 processor" 和确实应该期待possible changes in behavior

此外,将这样的全局 class 路径库添加到服务器的 JVM 违背了最近服务器版本的理念,例如 WildFly 10 / JBoss EAP7,其中扩展 'modules' 应该是首选方法。

如果 - 就像在我的 JBoss EAP7 上下文中一样 - 您更喜欢避免对数百个 XSLT 1.0 模板进行回归测试并受益于 2.0 功能,只是 create a new module to host the saxon libraries, add it to the list of global modules 您的 EE 子系统,假设您确实在 EJB 中执行您的转换;在这种情况下,您的部署工件需要 saxon 库作为依赖项,但 Maven 范围 'provided' 适用。或者,您可能希望将 saxon jar 与 WAR 或 EAR(Maven Scope 'compile')一起部署,而忘记全局模块。

无论哪种情况,只要您想从 XSLT2.0 功能中受益,只需替换:

javax.xml.transform.TransformerFactory tf = javax.xml.transform.TransformerFactory.newInstance();

来自

javax.xml.transform.TransformerFactory tf = net.sf.saxon.TransformerFactoryImpl.newInstance();

其余代码完全相同。

要强制执行 XSLT 1.0 转换,请使用(检查随变体版本和工厂品牌而变化的工厂 Impl 的 xalan 包路径)

javax.xml.transform.TransformerFactory tf = org.apache.xalan.processor.TransformerFactoryImpl.newInstance();

javax.xml.transform.TransformerFactory tf = javax.xml.transform.TransformerFactory.newInstance(
                    "org.apache.xalan.processor.TransformerFactoryImpl",
                    ClassLoader.getSystemClassLoader());