开发者

Resolving relative paths when loading XSLT files

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 tra开发者_JAVA百科nsformer = 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"/>


When you load an XSLT as a StreamSource and do not set a SystemID, the processor doesn't know "where" the XSLT is and cannot resolve relative paths.

http://www.onjava.com/pub/a/onjava/excerpt/java_xslt_ch5/index.html?page=5

By providing a system identifier as a parameter to the StreamSource, you are telling the XSLT processor where to look for commonFooter.xslt. Without this parameter, you may encounter an error when the processor cannot resolve this URI. The simple fix is to call the setSystemId( ) method as follows:

// construct a Source that reads from an InputStream
Source mySrc = new StreamSource(anInputStream);
// specify a system ID (a String) so the 
// Source can resolve relative URLs
// that are encountered in XSLT stylesheets
mySrc.setSystemId(aSystemId);


I'm using Saxon 9.x and still had issues when I used document within the stylesheet. The stylesheet was correctly resolved but the xmls bundled along with the stylesheet in the jar file didn't load as expected even with setSystemId. It resulted in file not found exception. It was easier for me to custom code the resolver with the code below:

JarfileResolver jarfileResolver = new JarfileResolver();
transformer.setURIResolver(jarfileResolver);


public class JarfileResolver implements URIResolver
{
    public Source resolve(String fileName, String base) throws TransformerException
    {
        URL url = getClass().getClassLoader().getResource(fileName);
        StreamSource jarFileSS = new StreamSource();

        try
        {
            InputStream jarfileIS = url.openStream();
            jarFileSS.setInputStream(jarfileIS);
        }
        catch(IOException ioExp)
        {
            throw new TransformerException(ioExp);
        }
        return jarFileSS;
    }
}


With xmlschema-core-2.2.4.jar the interface URIResolver changed and has 3 arguments now: targetNamespace, schemaLocation, baseUri.

Following @JunLei answer it would be now:

TransformerFactory transFact = TransformerFactory.newInstance();
URIResolver classpathResourceURIResolver= (targetNamespace, schemaLocation, baseUri) -> new InputSource(MyClass.class.getClassLoader().getResourceAsStream(schemaLocation));
transFact.setURIResolver(classpathResourceURIResolver);
...
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜