我有一堆 XSL。其中之一恰好使用 base-uri()。
当直接对文件运行时,它会显示文档的 systemId。当在另一个 XSL 之后运行时,它会显示该 XSL 的 systemId。
我无法控制的事情
- XSL 内容
- XSL 的顺序
- 必须使用 XSLT2 (saxon)
另外,我更喜欢流媒体解决方案。这可以通过将每个中间结果写入磁盘并将 systemId 伪装成原始文档来解决,但这是非常低效的。
这是我迄今为止尝试过的。
public class BadSystemIdDemo {
private static final SAXTransformerFactory XSLT2 =
new net.sf.saxon.TransformerFactoryImpl();
public static void main(String[] args) throws Exception {
Result to = new StreamResult(System.out);
// outputs: "file:///one.xsl"
usingXMLFilter(to);
System.out.println();
// also outputs: "file:///one.xsl"
usingTransformerHandler(to);
System.out.println();
// wanted: "file:///in.xml"
}
private static void usingTransformerHandler(Result to) throws Exception {
TransformerHandler first = XSLT2.newTransformerHandler(Inputs.xsl1());
TransformerHandler second = XSLT2.newTransformerHandler(Inputs.xsl2());
first.setResult(new SAXResult(second));
second.setResult(to);
XSLT2.newTransformer().transform(Inputs.in(), new SAXResult(first));
}
private static void usingXMLFilter(Result to) throws Exception {
XMLReader r = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
XMLFilter first = XSLT2.newXMLFilter(Inputs.xsl1());
XMLFilter second = XSLT2.newXMLFilter(Inputs.xsl2());
first.setParent(r);
second.setParent(first);
XSLT2.newTransformer().transform(Inputs.in(second), to);
}
}
只是例子,真实的事情显然更复杂。
public class Inputs {
private static final String IN_SYSTEM_ID = "file:///in.xml";
private static final String XSL1_SYSTEM_ID = "file:///one.xsl";
private static final String XSL2_SYSTEM_ID = "file:///two.xsl";
static Source in() {
return new StreamSource(new StringReader("<root/>"), IN_SYSTEM_ID);
}
static Source in(XMLReader using) {
return new SAXSource(using, SAXSource.sourceToInputSource(in()));
}
static Source xsl1() {
String contents = ""
+ "<xsl:stylesheet version=\"2.0\""
+ " xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">"
+ " <xsl:template match=\"@*|node()\">"
+ " <xsl:copy>"
+ " <xsl:apply-templates select=\"@*|node()\"/>"
+ " </xsl:copy>"
+ " </xsl:template>"
+ "</xsl:stylesheet>";
return new StreamSource(new StringReader(contents), XSL1_SYSTEM_ID);
}
static Source xsl2() {
String contents = ""
+ "<xsl:stylesheet version=\"2.0\""
+ " xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">"
+ " <xsl:template match=\"*\">"
+ " <xsl:value-of select=\"base-uri(.)\"/>"
+ " </xsl:template>"
+ "</xsl:stylesheet>";
return new StreamSource(new StringReader(contents), XSL2_SYSTEM_ID);
}
}