Java 加载 XSLT 文件时解析相对路径

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3699860/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 03:38:07  来源:igfitidea点击:

Resolving relative paths when loading XSLT files

javaxsltxsl-foapache-fop

提问by Javi

I need to do an XSL transformation using Apache FOP and I had code like this:

我需要使用 Apache FOP 进行 XSL 转换,我有这样的代码:

//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 xslPathis the path where my XSLT file is stored.

这里xslPath是我的XSLT文件的存储路径。

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.

我已经确认当我只有一个 XSLT 文件时它可以工作,但是在我的项目中,我将内容分成了几个 XSLT 文件并用<xsl:import />标记将它们连接起来。使用此配置,我得到一个 NullPointerException,因为它无法理解存储在 XSLT 中的所有信息,因为它分布在不同的文件中。

I wonder if there's any way to load all these files in the Source xsltSrcvariable so all the XSL information is available.

我想知道是否有任何方法可以将所有这些文件加载​​到Source xsltSrc变量中,以便所有 XSL 信息都可用。

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:

我已经根据 Mads Hansen 给出的答案更改了代码,但它仍然不起作用。我必须在类路径中包含 XSLT slt 文件,因此我使用 ClassLoader 加载 XSLT 文件。我在执行url.toExternalForm(). 这是我的新代码:

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.xsltbut it still doesn't resolve the relative paths to the other XSLT files.

它会查找并加载,myfile.xslt但仍无法解析其他 XSLT 文件的相对路径。

What am I doing wrong?

我究竟做错了什么?

回答by Mads Hansen

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

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

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

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:

通过将系统标识符作为参数提供给 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);

回答by JunLei

I just got it, a late answer(tested on FOP 1.0) ------

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

All you need is to set an uri resolver for your factory, as following works for me:

您只需要为您的工厂设置一个 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));
  }
}

and my importing xsl(so the 'imported.xsl' should be in the classpath):

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

<xsl:import href="META-INF/companybusinesscredit/imported.xsl"/>

回答by Anand

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:

我正在使用 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;
    }
}