如何在XSLT的xsl:import中使用类路径URI导入样式文件?
为Xalan指定类路径下的XSL导入路径
问题场景
在Gradle项目sample_gradle_project中使用Xalan(XSLT 1.0处理器)时,通过项目根路径src/main/resources/Afolder/step.xsl导入XSL文件在本地正常运行,但开发环境抛出IO异常,需要改用类路径方式指定<xsl:import>的href。
项目结构
sample_gradle_project -src/main -- java -----service --------- class.java -- resources ----- Afolder ---------- step.xsl
现有问题代码
Java代码:
import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.io.IOUtils; import java.io.InputStream; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamSource; String unescaped_xsl = StringEscapeUtils.unescapeXml("<xsl:import href = "src/main/resources/Afolder/step.xsl"/>"); InputStream inputStream = IOUtils.toInputStream(unescaped_xsl); Transformer transformer = transformerFactory.newTransformer(new StreamSource(inputStream));
报错信息:
Had IO Exception with stylesheet file: src/main/resources/Afolder/step.xsl
解决方案
1. 修正<xsl:import>的href路径
resources目录下的文件编译打包后会被放到类路径根目录,因此不需要src/main/resources前缀,直接使用类路径相对路径:
<xsl:import href="Afolder/step.xsl"/>
2. 为StreamSource设置类路径上下文URL
动态生成的样式表字符串没有默认的资源上下文,Xalan无法解析相对路径。需要通过类加载器获取资源URL,作为StreamSource的systemId,提供解析基准:
修改后的Java代码:
import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.io.IOUtils; import java.io.InputStream; import java.net.URL; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamSource; // 更新导入路径为类路径相对路径 String unescaped_xsl = StringEscapeUtils.unescapeXml("<xsl:import href = "Afolder/step.xsl"/>"); InputStream inputStream = IOUtils.toInputStream(unescaped_xsl); // 获取目标XSL的类路径URL,提取目录作为上下文 URL xslUrl = YourClass.class.getClassLoader().getResource("Afolder/step.xsl"); if (xslUrl == null) { throw new RuntimeException("类路径中未找到Afolder/step.xsl"); } String systemId = xslUrl.toString().replace("step.xsl", ""); // 为StreamSource设置系统ID,提供路径解析上下文 StreamSource source = new StreamSource(inputStream); source.setSystemId(systemId); Transformer transformer = transformerFactory.newTransformer(source);
3. 推荐方案:直接加载类路径下的主样式表
如果主样式表也放在resources目录中,建议直接通过类加载器加载,而非动态生成字符串,Xalan会自动基于类路径解析导入:
假设主样式表main.xsl放在resources/styles/下,内容:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:import href="../Afolder/step.xsl"/> <!-- 自定义模板逻辑 --> </xsl:stylesheet>
对应的Java代码:
import java.io.InputStream; import java.net.URL; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamSource; // 从类路径加载主样式表 InputStream mainXslStream = YourClass.class.getClassLoader().getResourceAsStream("styles/main.xsl"); URL mainXslUrl = YourClass.class.getClassLoader().getResource("styles/main.xsl"); if (mainXslStream == null || mainXslUrl == null) { throw new RuntimeException("类路径中未找到styles/main.xsl"); } StreamSource source = new StreamSource(mainXslStream); source.setSystemId(mainXslUrl.toString()); Transformer transformer = transformerFactory.newTransformer(source);
核心说明
- resources目录下的资源编译后位于类路径根,引用时无需
src/main/resources前缀。 - Xalan解析相对路径依赖
StreamSource的systemId作为基准,必须设置为类路径资源的URL才能正确定位导入文件。 - 动态生成样式表字符串易引发路径解析问题,优先直接加载类路径下的XSL文件。
内容的提问来源于stack exchange,提问作者sheenaLal
相关产品推荐
相关产品推荐

