我使用saxon (HE9.9.1-6)将XML转换为HTML文件。之所以使用Saxon,是因为XSLT是版本2,默认的java类失败。
XSLT包含两个要在其他文件内容中复制的语句:
<xsl:value-of select="unparsed-text('file.ext')"/>只要Xslt和那些文件位于同一个目录中,只要xslt作为文件源提供,它就能正常工作。
Source xslt = new StreamSource(new File("c:/somedir/file.xsl"));但是我的xslt位于一个资源目录中(稍后它应该被打包到一个jar中)。如果我在这个上下文中使用它,saxon无法找到包含的文件,因为它在我的项目的根目录中查找:
Source xslt = new StreamSource(getClass().getClassLoader().getResourceAsStream("file.xsl"));在以下方面的成果:
Error evaluating (fn:unparsed-text(...)) in xsl:value-of/@select on line 22 column 66
FOUT1170: Failed to read input file: <project root directory>\included_file.css (File not found)我是否可以为saxon提供额外的StreamSources,以满足它需要包含的文件?我什么也找不到。
理想情况下,我想要这样的东西:
transformer.addInput(new StreamSource(getClass().getClassLoader().getResourceAsStream("inputfile.css")));我想出的唯一解决方案非常难看:将xslt及其所需的文件从资源复制到临时目录,然后使用它作为源代码进行转换。
示例代码
我不熟悉XSLT的编写,所以我只能提供非最小的示例文件。
xslt及其两个重定向文件(css和js)可以找到这里。你需要的是三个"xrechnung“。直接链接:xrechnung-html.xsl,xrechnung-viewer.css,xrechnung-viewer.js。
请将它们放在一个资源目录中(以防万一,在eclipse中:创建一个资源文件夹,并将其作为一个源目录添加到properties->build路径中)。
该xml是由上面项目的第一步生成的,使用它自己的示例文件,我将它放在pastebin 这里上
(最初直接包含,但得到字符限制错误)
最后,Java代码(包括丑陋的解决方案):
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Comparator;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import org.xml.sax.SAXException;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.Serializer;
import net.sf.saxon.s9api.Xslt30Transformer;
import net.sf.saxon.s9api.XsltCompiler;
import net.sf.saxon.s9api.XsltExecutable;
public class SaxonProblem {
public static void main(String[] args) throws IOException, SaxonApiException, SAXException {
Path xml = Paths.get("path/to/the.xml");
//working(xml);
notWorking(xml);
}
public static void working(Path xmlFile) throws IOException, SaxonApiException, SAXException {
Path dir = Files.createTempDirectory("saxon");
System.out.println("Temp dir: " + dir.toString());
Path xsltFile = dir.resolve("xrechnung-html.xsl");
Files.copy(SaxonProblem.class.getClassLoader().getResourceAsStream("xrechnung-html.xsl"),
xsltFile, StandardCopyOption.REPLACE_EXISTING);
Files.copy(SaxonProblem.class.getClassLoader().getResourceAsStream("xrechnung-viewer.css"),
dir.resolve("xrechnung-viewer.css"), StandardCopyOption.REPLACE_EXISTING);
Files.copy(SaxonProblem.class.getClassLoader().getResourceAsStream("xrechnung-viewer.js"),
dir.resolve("xrechnung-viewer.js"), StandardCopyOption.REPLACE_EXISTING);
// for the sake of brevity, the html is made where the xml was
Path html = xmlFile.resolveSibling(xmlFile.getFileName().toString() + ".html");
Source xslt = new StreamSource(xsltFile.toFile());
Source xml = new StreamSource(xmlFile.toFile());
transformXml(xml, xslt, html);
// cleanup
Files.walk(dir).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
}
public static void notWorking(Path xmlFile) throws SaxonApiException, SAXException, IOException {
// for the sake of brevity, the html is made where the xml was
Path html = xmlFile.resolveSibling(xmlFile.getFileName().toString() + ".html");
Source xslt = new StreamSource(SaxonProblem.class.getClassLoader().getResourceAsStream("xrechnung-html.xsl"));
Source xml = new StreamSource(xmlFile.toFile());
transformXml(xml, xslt, html);
}
public static void transformXml(Source xml, Source xslt, Path output) throws SaxonApiException, SAXException, IOException {
Processor processor = new Processor(false);
XsltCompiler compiler = processor.newXsltCompiler();
XsltExecutable stylesheet = compiler.compile(xslt);
Serializer out = processor.newSerializer(output.toFile());
out.setOutputProperty(Serializer.Property.METHOD, "html");
out.setOutputProperty(Serializer.Property.INDENT, "yes");
Xslt30Transformer transformer = stylesheet.load30();
transformer.transform(xml, out);
}
}溶液
感谢Martin的评论和Michael的回答,我有一个使用UnparsedTextURIResolver的解决方案。确实感觉更像是黑客,但它很有效,而且比我以前的解决办法更好:
Processor processor = new Processor(false);
UnparsedTextURIResolver defaultUtur = processor.getUnderlyingConfiguration().getUnparsedTextURIResolver();
processor.getUnderlyingConfiguration().setUnparsedTextURIResolver(new UnparsedTextURIResolver() {
@Override
public Reader resolve(URI arg0, String arg1, Configuration arg2) throws XPathException {
if (arg0.toString().endsWith("myfilename.css")) {
InputStream css = SaxonProblem.class.getClassLoader().getResourceAsStream("myfilename.css");
return new InputStreamReader(css);
}
return defaultUtur.resolve(arg0, arg1, arg2);
}
});
//[...]发布于 2020-01-31 17:18:23
一些建议:
classpath:方案中使用URI (使用URI的所有路径都可能支持最近添加的URI)UnparsedTextResolver;Saxon将把查找资源的任务委托给这个解析器。resolve-uri()函数获得绝对URIhttps://stackoverflow.com/questions/60005486
复制相似问题