链/管道变换的最佳方式

问题描述 投票:0回答:2

我在 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。

现代推荐是什么?

saxon
2个回答
2
投票

您已经排除了使用单独的管道语言(例如 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() 有点警惕是正确的,与其说是出于性能原因,不如说是因为它很难调试。


0
投票

仅供参考,在你们的帮助下,这是我现在得到的结果。

在此示例中,没有输入 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());
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.