I need to do an XSL transformation using Apache FOP and I had code like this:
//Setup FOP
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out);
//Setup Transformer
Source xsltSrc = new StreamSource(new File(xslPath));
Transformer transformer = tFactory.newTransformer(xsltSrc);
//Make sure the XSL transformation's result is piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
//Setup input
Source src = new StreamSource(new File(xmlPath));
//Start the transformation and rendering process
transformer.transform(src, res);
where xslPath
is the path where my XSLT file is stored.
I have confirmed that it works when I have only one XSLT file, but in my project I have divided things into several XSLT files and joined them with the <xsl:import />
tag. With this configuration, I get a NullPointerException because it doesn't understand all the information stored in XSLT because it's distributed over different files.
I wonder if there's any way to load all these files in the Source xsltSrc
variable so all the XSL information is available.
UPDATE
I've changed the code based on the answer given by Mads Hansen, but it still doesn't work. I have to include the XSLT slt files in the classpath, so I load the XSLT file with ClassLoader. I've checked that the URL has the correct path when executing url.toExternalForm()
. This is my new piece of code:
ClassLoader cl = this.getClass().getClassLoader();
String systemID = "resources/xslt/myfile.xslt";
InputStream in = cl.getResourceAsStream(systemID);
URL url = cl.getResource(systemID);
Source source = new StreamSource(in);
source.setSystemId(url.toExternalForm());
transformer = tFactory.newTransformer(source);
It finds and loads myfile.xslt
but it still doesn't resolve the relative paths to the other XSLT files.
What am I doing wrong?
I just got it, a late answer(tested on FOP 1.0) ------
All you need is to set an uri resolver for your factory, as following works for me:
TransformerFactory transFact = TransformerFactory.newInstance();
StreamSource xsltSource = new StreamSource(xsl);
// XXX for 'xsl:import' to load other xsls from class path
transFact.setURIResolver(new ClasspathResourceURIResolver());
Templates cachedXSLT = transFact.newTemplates(xsltSource);
Transformer transformer = cachedXSLT.newTransformer();
class ClasspathResourceURIResolver implements URIResolver {
@Override
public Source resolve(String href, String base) throws TransformerException {
return new StreamSource(XXX.getClassLoader().getResourceAsStream(href));
}
}
and my importing xsl(so the 'imported.xsl' should be in the classpath):
<xsl:import href="META-INF/companybusinesscredit/imported.xsl"/>