17

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?

4

3 回答 3

20

我刚刚得到它,一个迟到的答案(在 FOP 1.0 上测试)------

您只需要为您的工厂设置一个 uri 解析器,如下所示:

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

和我的导入 xsl(所以“imported.xsl”应该在类路径中):

<xsl:import href="META-INF/companybusinesscredit/imported.xsl"/>
于 2012-09-17T06:06:10.363 回答
13

当您将 XSLT 作为StreamSource加载且未设置SystemID时,处理器不知道 XSLT 的“位置”并且无法解析相对路径。

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

通过将系统标识符作为参数提供给 StreamSource,您可以告诉 XSLT 处理器在哪里查找 commonFooter.xslt。如果没有此参数,您可能会在处理器无法解析此 URI 时遇到错误。简单的解决方法是调用 setSystemId() 方法,如下所示:

// 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);
于 2010-09-13T12:19:31.193 回答
2

我正在使用 Saxon 9.x,但在样式表中使用文档时仍然遇到问题。样式表已正确解析,但与 jar 文件中的样式表捆绑在一起的 xml 未按预期加载,即使使用 setSystemId。它导致文件未找到异常。使用以下代码自定义解析器代码对我来说更容易:

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;
    }
}
于 2012-12-07T19:35:37.737 回答