Java 中的高效 XSLT 管道(或将结果重定向到源)

发布于 2024-08-02 11:08:04 字数 1023 浏览 8 评论 0原文

我有一系列相互馈送的 XSL 2.0 样式表,即样式表 A 的输出馈送 B 馈送 C。

最有效的方法是什么?重新表述的问题是:如何有效地将一种转换的输出路由到另一种转换中。

这是我的第一次尝试:

@Override
public void transform(Source data, Result out) throws TransformerException{
    for(Transformer autobot : autobots){
        if(autobots.indexOf(autobot) != (autobots.size()-1)){
            log.debug("Transforming prelim stylesheet...");
            data = transform(autobot,data);
        }else{
            log.debug("Transforming final stylesheet...");
            autobot.transform(data, out);
        }
    }
}

private Source transform(Transformer autobot, Source data) throws TransformerException{
    DOMResult result = new DOMResult();
    autobot.transform(data, result);
    Node node = result.getNode();
    return new DOMSource(node);
}

正如您所看到的,我使用 DOM 来进行转换,虽然它很方便,但它的性能并不是最佳的。

有没有简单的方法可以将 SAXResult 路由到 SAXSource? StAX 解决方案将是另一种选择。

我知道像 XProc 这样的项目,如果您还没有看过的话,这非常酷,但我没有不想投资整个框架。

I have a series of XSL 2.0 stylesheets that feed into each other, i.e. the output of stylesheet A feeds B feeds C.

What is the most efficient way of doing this? The question rephrased is: how can one efficiently route the output of one transformation into another.

Here's my first attempt:

@Override
public void transform(Source data, Result out) throws TransformerException{
    for(Transformer autobot : autobots){
        if(autobots.indexOf(autobot) != (autobots.size()-1)){
            log.debug("Transforming prelim stylesheet...");
            data = transform(autobot,data);
        }else{
            log.debug("Transforming final stylesheet...");
            autobot.transform(data, out);
        }
    }
}

private Source transform(Transformer autobot, Source data) throws TransformerException{
    DOMResult result = new DOMResult();
    autobot.transform(data, result);
    Node node = result.getNode();
    return new DOMSource(node);
}

As you can see, I'm using a DOM to sit in between transformations, and although it is convenient, it's non-optimal performance wise.

Is there any easy way to route to say, route a SAXResult to a SAXSource? A StAX solution would be another option.

I'm aware of projects like XProc, which is very cool if you haven't taken a look at yet, but I didn't want to invest in a whole framework.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

情话已封尘 2024-08-09 11:08:04

我发现了这个:#3。链接转换展示了使用 TransformerFactory 链接转换的两种方法,将一个转换的结果提供给下一个转换,然后最终输出到系统输出。这避免了在转换之间对字符串、文件等进行中间序列化的需要。

当多个、连续的
需要进行转换
相同的 XML 文档,一定要避免
不必要的解析操作。我
经常遇到这样的代码
将一个字符串转换为另一个字符串,
然后将该字符串转换为 Yet
另一个字符串。这不仅慢,
但它可能会消耗大量
内存量也是如此,特别是
如果中间字符串不是
允许垃圾收集。

大多数转换都基于
系列 SAX 活动。 SAX 解析器
通常会解析一个InputStream或
SAX 事件中的另一个 InputSource,
然后可以将其馈送到
变压器。而不是拥有
转换器输出到文件、字符串、
或另一个这样的结果,一个 SAXResult
可以用它代替。 SAX结果
接受一个 ContentHandler,它可以
将这些 SAX 事件直接传递给
另一个变压器等。

这是一种方法,也是我的方法
通常更喜欢,因为它提供了更多
各种输入的灵活性和
输出源。这也使得
相当容易创建转换
动态链接并带有变量
转换次数。

SAXTransformerFactory stf = (SAXTransformerFactory)TransformerFactory.newInstance();

// 这些模板对象可以重用并从其他地方获取。
模板 templates1 = stf.newTemplates(new StreamSource(
  getClass().getResourceAsStream("MyStylesheet1.xslt")));
模板 templates2 = stf.newTemplates(new StreamSource(
  getClass().getResourceAsStream("MyStylesheet1.xslt")));

TransformerHandler th1 = stf.newTransformerHandler(templates1);
TransformerHandler th2 = stf.newTransformerHandler(templates2);

th1.setResult(new SAXResult(th2));
th2.setResult(new StreamResult(System.out));

变压器 t = stf.newTransformer();
t.transform(new StreamSource(System.in), new SAXResult(th1));

// th1 为 th2 提供数据,而 th2 又为 System.out 提供数据。

I found this: #3. Chaining Transformations that shows two ways to use the TransformerFactory to chain transformations, having the results of one transform feed the next transform and then finally output to system out. This avoids the need for an intermediate serialization to String, file, etc. between transforms.

When multiple, successive
transformations are required to the
same XML document, be sure to avoid
unnecessary parsing operations. I
frequently run into code that
transforms a String to another String,
then transforms that String to yet
another String. Not only is this slow,
but it can consume a significant
amount of memory as well, especially
if the intermediate Strings aren't
allowed to be garbage collected.

Most transformations are based on a
series of SAX events. A SAX parser
will typically parse an InputStream or
another InputSource into SAX events,
which can then be fed to a
Transformer. Rather than having the
Transformer output to a File, String,
or another such Result, a SAXResult
can be used instead. A SAXResult
accepts a ContentHandler, which can
pass these SAX events directly to
another Transformer, etc.

Here is one approach, and the one I
usually prefer as it provides more
flexibility for various input and
output sources. It also makes it
fairly easy to create a transformation
chain dynamically and with a variable
number of transformations.

SAXTransformerFactory stf = (SAXTransformerFactory)TransformerFactory.newInstance();

// These templates objects could be reused and obtained from elsewhere.
Templates templates1 = stf.newTemplates(new StreamSource(
  getClass().getResourceAsStream("MyStylesheet1.xslt")));
Templates templates2 = stf.newTemplates(new StreamSource(
  getClass().getResourceAsStream("MyStylesheet1.xslt")));

TransformerHandler th1 = stf.newTransformerHandler(templates1);
TransformerHandler th2 = stf.newTransformerHandler(templates2);

th1.setResult(new SAXResult(th2));
th2.setResult(new StreamResult(System.out));

Transformer t = stf.newTransformer();
t.transform(new StreamSource(System.in), new SAXResult(th1));

// th1 feeds th2, which in turn feeds System.out.
不顾 2024-08-09 11:08:04

相关问题 Efficient XSLT pipeline, with params, in Java 澄清了正确的问题传递给此类变压器链的参数。

它还暗示了没有第三个变压器的稍微较短的解决方案:

SAXTransformerFactory stf = (SAXTransformerFactory)TransformerFactory.newInstance();

Templates templates1 = stf.newTemplates(new StreamSource(
        getClass().getResourceAsStream("MyStylesheet1.xslt")));
Templates templates2 = stf.newTemplates(new StreamSource(
        getClass().getResourceAsStream("MyStylesheet2.xslt")));

TransformerHandler th1 = stf.newTransformerHandler(templates1);
TransformerHandler th2 = stf.newTransformerHandler(templates2);

th2.setResult(new StreamResult(System.out));

// Note that indent, etc should be applied to the last transformer in chain:
th2.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes");

th1.getTransformer().transform(new StreamSource(System.in), new SAXResult(th2));

Related question Efficient XSLT pipeline, with params, in Java clarified on correct parameters passing to such transformer chain.

And it also gave a hint on slightly shorter solution without third transformer:

SAXTransformerFactory stf = (SAXTransformerFactory)TransformerFactory.newInstance();

Templates templates1 = stf.newTemplates(new StreamSource(
        getClass().getResourceAsStream("MyStylesheet1.xslt")));
Templates templates2 = stf.newTemplates(new StreamSource(
        getClass().getResourceAsStream("MyStylesheet2.xslt")));

TransformerHandler th1 = stf.newTransformerHandler(templates1);
TransformerHandler th2 = stf.newTransformerHandler(templates2);

th2.setResult(new StreamResult(System.out));

// Note that indent, etc should be applied to the last transformer in chain:
th2.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes");

th1.getTransformer().transform(new StreamSource(System.in), new SAXResult(th2));
分分钟 2024-08-09 11:08:04

最好的选择是坚持使用 DOM,因为 XSLT 处理器无论如何都必须构建一棵树 - 流式处理只是非常有限的转换类别的一个选项,而且很少有处理器能够自动找出并切换仅流式传输的实现;否则他们只是读取输入并构建树。

Your best bet is to stick to DOM as you're doing, because an XSLT processor would have to build a tree anyway - streaming is only an option for very limited category of transforms, and few if any processors can figure it out automatically and switch to a streaming-only implementation; otherwise they just read the input and build the tree.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文