加载 XSLT 文件时解析相对路径
Posted
技术标签:
【中文标题】加载 XSLT 文件时解析相对路径【英文标题】:Resolving relative paths when loading XSLT files 【发布时间】:2011-04-11 14:54:54 【问题描述】:我需要使用 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);
xslPath
是存储我的 XSLT 文件的路径。
我已经确认当我只有一个 XSLT 文件时它可以工作,但在我的项目中,我已将内容分成几个 XSLT 文件并使用<xsl:import />
标签将它们连接起来。使用此配置,我会收到 NullPointerException,因为它无法理解 XSLT 中存储的所有信息,因为它分布在不同的文件中。
我想知道是否有任何方法可以将所有这些文件加载到 Source xsltSrc
变量中,以便所有 XSL 信息都可用。
更新
我已根据 Mads Hansen 给出的答案更改了代码,但仍然无法正常工作。我必须在类路径中包含 XSLT slt 文件,所以我使用 ClassLoader 加载 XSLT 文件。我在执行url.toExternalForm()
时检查了该URL 的路径是否正确。这是我的新代码:
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);
它会找到并加载myfile.xslt
,但它仍然无法解析到其他 XSLT 文件的相对路径。
我做错了什么?
【问题讨论】:
【参考方案1】:我使用的是 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;
【讨论】:
【参考方案2】:我刚刚得到它,一个迟到的答案(在 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"/>
【讨论】:
非常感谢,这为我节省了几个小时。【参考方案3】:当您将 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);
【讨论】:
感谢您的回答,但它似乎并没有解决我的问题,尽管您的回答是有道理的。我已经用我对代码的更改更新了我的问题。 您可能需要获取 SystemID 的绝对路径。除非您知道它将在哪里解析“来自”的相对路径。尝试将该相对路径转换为绝对路径,例如:String xsltSystemId = new File(systemID).toURL().toExternalForm( );
或 String xsltSystemId = new File(relativePath).getAbsolutePath();
谢谢,我已经这样做了,并且我检查了当我执行 url.toExternalForm() 时它会获得一个绝对路径。但我现在不知道问题出在哪里。
这个解决方案非常适合我:xsltStreamSource.setSystemId(xsltFile.toURI().toString());
@james.garriss 经过几个小时的爬网和阅读浪费的 cmets 并没有简单地回答如何导入相关文件,突然间,你这个“单行”解决了我的相关“导入”问题。如果可以的话,我会给你 10000 票! :D以上是关于加载 XSLT 文件时解析相对路径的主要内容,如果未能解决你的问题,请参考以下文章