Java中XSLT转换XML时无法找到href引用的functions.xslt文件
你遇到的核心问题是:当前代码把deployments.xslt作为纯字符串加载到StringReader中,Transformer缺少上下文信息,无法解析相对路径的functions.xslt——尤其是打包成Jar包后,资源都在类路径下,相对路径的解析规则和本地文件系统完全不同,导致找不到依赖文件。
方案1:设置StreamSource的SystemId(推荐)
当XSLT文件存放在Jar包的类路径下时,给StreamSource设置正确的systemId,让Transformer以此为基础解析相对路径的依赖文件。假设deployments.xslt和functions.xslt都在Jar包的/xslt/目录下,修改init方法:
private void init(String xslt) throws IOException, TransformerConfigurationException, AggregatorException { if (xslt == null || xslt.isEmpty()) { throw new AggregatorException("XSLT was null or empty. Unable to transform condensed model to yaml"); } // 获取XSLT文件所在类路径的基础URI String baseUri = getClass().getResource("/xslt/").toExternalForm(); StreamSource source = new StreamSource(new StringReader(xslt)); // 设置systemId,让Transformer以此为根路径解析相对引用 source.setSystemId(baseUri); transformer = factory.newTransformer(source); Security.addProvider(new BouncyCastleProvider()); }
注意:将/xslt/替换为你实际存放两个XSLT文件的类路径目录;如果文件直接在Jar根目录下,使用getClass().getResource("/").toExternalForm()即可。
方案2:内联functions.xslt代码
如果不想处理路径逻辑,直接把functions.xslt的全部内容复制到deployments.xslt中,替换掉<xsl:include href="functions.xslt"/>这一行。这样整个XSLT是单文件结构,没有外部依赖,打包后不会出现文件找不到的问题。
方案3:自定义URIResolver
实现URIResolver接口,让Transformer通过自定义逻辑加载依赖的XSLT文件,适合复杂的资源加载场景:
private void init(String xslt) throws IOException, TransformerConfigurationException, AggregatorException { if (xslt == null || xslt.isEmpty()) { throw new AggregatorException("XSLT was null or empty. Unable to transform condensed model to yaml"); } // 自定义URI解析逻辑,从类路径加载依赖文件 factory.setURIResolver(new URIResolver() { @Override public Source resolve(String href, String base) throws TransformerException { InputStream is = getClass().getResourceAsStream("/xslt/" + href); if (is == null) { throw new TransformerException("Could not find XSLT resource: " + href); } return new StreamSource(is); } }); transformer = factory.newTransformer(new StreamSource(new StringReader(xslt))); Security.addProvider(new BouncyCastleProvider()); }
当Transformer遇到<xsl:include>标签时,会自动调用你实现的resolve方法,你可以在这里从类路径、数据库或其他自定义位置加载依赖文件。
内容的提问来源于stack exchange,提问作者Gene Smith

