4

I am trying date formatting in XSLT 2.0. When I try to run it in my workspace it runs fine and I get a proper response. But when I try to achieve the same after deploying the my jar on JBoss eap 6.1, I get below error:

16:35:02,311 ERROR [XSLTUtil] (DefaultQuartzScheduler-camel-12_Worker-2) XSLTUtil|0|TransformerException : Error occured while transforming xml with the xslt file : javax.xml.transform.TransformerException: org.xml.sax.SAXException: Could not find function: format-dateTime javax.xml.transform.TransformerException: Could not find function: format-dateTime|

My Xsl file : here I am trying to format the the current date to some other format using 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>

Here is XSLT util class which I am using for transforming/mapping my XML and XSL files. In the below java file I am reading the xsl file from my local directory. Once I deploy my jar to JBoss server, I pass read the file location and pass it to XSLTFilename variable.

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);

    }

}

This particular piece of code works fine in my workspace. Do I need to configure something on my JBoss server in order to fix the issue? Please let me know what exactly I am missing.

dev
  • 1,343
  • 2
  • 19
  • 40
  • 1
    "*I am trying date formatting in XSLT using EXSLT.*" No, not really. You have merely declared two EXSLT namespaces, but you are not using them at all. Instead, you are using two **XSLT 2.0** functions (`format-dateTime()` and `current-dateTime()`) which apparently your processor does not support. Note also that not all XSLT 1.0 processors support all EXSLT extension functions; `date:format-date()` in particular is not supported by any processor that I know of. – michael.hor257k May 03 '15 at 16:25
  • You are write, I am not using any of the EXSLT functions. My actual issue was how to enable XSLT 2.0 processor in my JBoss eap 6.1 server. Which I was able to figure out by overriding javax.xml.transform.TransformerFactory with SAXON (net.sf.saxon.TransformerFactoryImpl). – dev May 04 '15 at 05:43
  • @amit4497 Contact Red hat support!! – Saravana Kumar May 07 '15 at 19:31

3 Answers3

5

In order to override XALAN processor, which is by default supported in JBoss EAP 6.1 we can add JAVA_OPTS="$JAVA_OPTS -Djavax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl" in standalone.conf This overrides the XALAN processor which supports XSLT 1.0 and with SAXON which supports XSLT 2.0. Thank you @Martin Honnen for giving me hint.

Community
  • 1
  • 1
dev
  • 1,343
  • 2
  • 19
  • 40
1

Setting the Java Option flag

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

in your App server launch script does also require the plain JVM to have access to e.g. both saxon-8.7.jar and saxon-dom-8.7.jar on the class path.

But in doing so, ALL your XSL templates will require <xsl:stylesheet version="2.0"...> otherwise you'll get "Warning: Running an XSLT 1.0 stylesheet with an XSLT 2.0 processor" and indeed shall expect possible changes in behavior.

Moreover, adding such global classpath libraries to the server's JVM runs against the philosophy of recent server releases like WildFly 10 / JBoss EAP7 where extension 'modules' shall be the preferred way.

If - like in my JBoss EAP7 context - you prefer avoiding regression testing of hundreds of XSLT 1.0 templates and benefit from 2.0 features, just create a new module to host the saxon libraries, add it to the list of global modules of your EE subsystem, assuming indeed that you execute your transformations in a EJB; in that case your deployment artifacts need saxon libraries as dependencies, but a Maven scope 'provided' applies. Alternatively, you may want to deploy the saxon jars alongside your WAR or EAR (Maven Scope 'compile') and forget about global modules.

In either case, whenever you want to benefit from XSLT2.0 features, just replace:

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

by

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

The rest of your code being identical.

To enforce back a XSLT 1.0 transformation, then use (check the xalan package path for the factory Impl that varies with variant versions and factory brands)

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

or

javax.xml.transform.TransformerFactory tf = javax.xml.transform.TransformerFactory.newInstance(
                    "org.apache.xalan.processor.TransformerFactoryImpl",
                    ClassLoader.getSystemClassLoader());
Bernard Hauzeur
  • 2,317
  • 1
  • 18
  • 25
  • Let's beware of a 2 issues: (a) the presence of Saxon libraries in your CLASSPATH, else in a WAR or EAR deployment, does change the default Transformer factory to Saxon (registering itself automatically as new default provider). So to enforce an XSLT 1.0 transformation you shall explicitly make reference to it, e.g. tf = javax.xml.transform.TransformerFactory.newInstance( "org.apache.xalan.processor.TransformerFactoryImpl", ClassLoader.getSystemClassLoader()); (b) I noted side effects of Saxon onto the DOM API behavior, notably linked to setNamespaceAware() – Bernard Hauzeur Jun 16 '17 at 22:58
0

The line <xsl:value-of select="format-dateTime(current-dateTime(), '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01].[f001][Z]')" /> together with the lines <xsl:stylesheet version='2.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:xs="http://www.w3.org/2001/XMLSchema" suggests you are trying to use the XSLT 2.0 dateTime data type and its functions. To have that working you need to use an XSLT 2.0 processor like Saxon 9. If you get an error about such functions not being defined then you are probably running the code with an XSLT 1.0 processor like Xalan. I am not familiar with jboss so I can't tell you how to set it up to use an XSLT 2.0 processor instead of an XSLT 1.0 processor.

Martin Honnen
  • 160,499
  • 6
  • 90
  • 110