我在 saxonica.com、Google 和 Chat GPT 上进行了一些研究,以找到在不引发序列化和解析的情况下进行链/管道转换的最佳方法。我找到了使用 s9api、JAXP 和 fn:transform() 来实现这一点的方法。我发现一些文章将中间结果实现为 DOM、SAX 和 XDM。我发现的一些文章已经有 14 年历史了,所以我不确定现在 2023 年哪个是理想的。我在 Jetty 上运行的 Java Servlet 中执行 Saxon,基于 saxonica.com 上的 Servlet 示例,该示例缓存了编译的模板。我不喜欢 fn:transform(),因为我认为它不能像 Java 中那样使用编译后的样式表;如果我弄错了,请告诉我(我确实有静态参数)。速度是我的第一要务。它不必是便携式的,因为我只会使用 Saxon。
现代推荐是什么?
您已经排除了使用单独的管道语言(例如 XProc 或 Orbeon)来编排工作流程的可能性。
您还忽略了使用该模式在单个 XSLT 样式表中执行一系列转换的可能性
<xsl:variable name="phase-a-output">
<xsl:apply-templates mode="phase-a"/>
</xsl:variable>
<xsl:variable name="phase-b-output">
<xsl:apply-templates select="$phase-a-output" mode="phase-b"/>
</xsl:variable>
<xsl:apply-templates select="$phase-b-output" mode="phase-c"/>
如果您习惯使用 Java 编码,那么我建议使用 s9api API。创建三个 Xslt30Transformer 实例 A、B、C,然后执行
A.applyTemplates(source,
B.asDocumentDestination(
C.asDocumentDestination(
serializer)))
您提到您正在使用静态参数。您应该注意,静态参数是在编译样式表时应用的,这意味着如果您重复使用相同的样式表并具有不同的静态参数值,则每次都会重新编译。
我认为你对 fn:transform() 有点警惕是正确的,与其说是出于性能原因,不如说是因为它很难调试。
仅供参考,在你们的帮助下,这是我现在得到的结果。
在此示例中,没有输入 XML,因此我传入
<root/>
只是为了获取上下文项,以便 transformer.appyTemplates()
命中某些内容 (如果 ss1.xsl 是用 ss1.xsl 编写的,我可以按名称调用模板命名模板).
ss2
的 XSL 样式表名称来自根元素的 d1
属性中第一次转换 @xsl
的结果。因此在进行第二次转换之前将其提取出来。这种方法还可以在调试时轻松检查中间结果,例如URL 参数可以序列化 d1
而不是 d2
。
我知道我可以跳过
d2
并立即序列化它,但这让我可以通过在序列化之前检查 d2
来做一些不同的事情,即使我在这里不这样做。
它工作出色,而且速度非常快。
ServletOutputStream out = res.getOutputStream();
Processor processor = new Processor(true);
String ss1 = "ss1.xsl";
XsltCompiler c1 = processor.newXsltCompiler();
XsltExecutable s1 = c1.compile(new StreamSource(new File(ss1)));
Xslt30Transformer t1 = s1.load30();
XdmNode rootNode = processor.newDocumentBuilder().build(new StreamSource(new StringReader("<root/>")));
XdmDestination d1 = new XdmDestination();
t1.applyTemplates(rootNode, d1);
String ss2 = d1.getXdmNode().children().iterator().next().getAttributeValue(new QName("xsl"));
XsltCompiler c2 = processor.newXsltCompiler();
XsltExecutable s2 = c2.compile(new StreamSource(new File(ss2)));
Xslt30Transformer t2 = s2.load30();
XdmDestination d2 = new XdmDestination();
t2.setGlobalContextItem(d1.getXdmNode());
t2.applyTemplates(d1.getXdmNode(), d2);
// Optionally do something based on d2 inspection, e.g. more transforms generating d3, d4, etc.
XdmDestination xdmOut = d2;
res.setContentType("text/xml");
Serializer serializer = processor.newSerializer(out);
serializer.setOutputProperty(Serializer.Property.METHOD, "xml");
serializer.serializeXdmValue(xdmOut.getXdmNode());