![](/img/trans.png)
[英]How to do XSLT 2.0 transform using saxon s9api? XML file to XML file
[英]Java using Saxon (s9api) to transform XML: How to add input files in resources?
我使用 saxon (HE 9.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)
有什么方法可以為撒克遜人提供額外的 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 中:創建一個資源文件夾並將其添加為屬性-> 構建路徑中的源目錄)。
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 Honnen 的評論和 Michael Kay 的回答,我有一個使用 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);
}
});
//[...]
一些建議:
使用帶有classpath:
方案的 URI(最近添加的,可能不是所有使用 URI 的路徑都支持)
使用配置注冊一個UnparsedTextResolver
; Saxon 將把尋找資源的任務委托給這個解析器
提供包含目錄的名稱作為樣式表的參數,並使用resolve-uri()
函數獲取絕對 URI
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.