2
votes

I've encountered a problem. I need to transform XML using XSLT 2.0 (SAXON-HE 9.8.0 processor) in Java. In my XSLT I am using (via import) external functions from functx.

When both files(xslt map and .xsl file with functx) are in the same directory everything works fine. In my .xsl, functx is correctly imported and it works:

xmlns:functx="http://www.functx.com"

xsl:import href="functx-package.xsl"

Is there a way to use external functions from functx in my .xsl map when both files are in memory as String objects or InputStreams or whatever?

I can't store the files on the drive in one directory as I did before.

The only possibility that might fix my problem is to paste functx file into my .xsl mapper, but this is wrong solution - [very]bad practice.

What do I use:

  • Java 7
  • SAXON-HE 9.8.0 processor
  • XSLT 2.0
2

2 Answers

3
votes

Supply a compile-time URIResolver with the logic

public Source resolve(String href, String base) {
  if (href.equals("functx-package.xsl")) {
     return new StreamSource(new StringReader(functxAsString));
  } else {
     return null;
  }
}

The compile-time URIResolver is the one supplied to the XsltCompiler if you are using s9api, or to the TransformerFactory if you are using JAXP.

0
votes

To sum up:

import documentation from Saxon

To use this resolver properly we need to set it in our TransformerFactory. Than each transformer is going to catch href in import and match the file with our .xsl files as strings. I'm also using outputURIResolver to catch the output and create multiple files in memory. (interesting usage of outputURIResolver - link)

example:

in .xsl file:

<xsl:import href="functx-package.xsl"/>
<xsl:import href="functs-package.xsl"/>

in java:

   TransformerFactory tFactory = TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", XMLviaXSLTransformer.class.getClassLoader());

    tFactory.setURIResolver(new URIResolver() {
        @Override
        public Source resolve(String href, String base) {
            if (href.equals("functx-package.xsl")) {
                return new StreamSource(new StringReader(finalFunctsAsString));
            } else if (href.equals("functs-package.xsl")) {
                return new StreamSource(new StringReader(finalFunctxAsString));
            } else {
                return null;
            }
        }
    });

    Transformer transformer = tFactory.newTransformer(xsltMap);
    StreamResult standardResult = new StreamResult(new ByteArrayOutputStream());
    transformer.transform(xmlInput, standardResult);

Thank you Michael for help. This URIResolver is very powerful.