20

我有一系列相互馈送的 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这样的项目,如果你还没有看过的话,这很酷,但我不想投资整个框架。

4

3 回答 3

24

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

当需要对同一个 XML 文档进行多次连续转换时,请务必避免不必要的解析操作。我经常遇到将一个字符串转换为另一个字符串,然后将该字符串转换为另一个字符串的代码。这不仅速度慢,而且还会消耗大量内存,尤其是在不允许对中间字符串进行垃圾收集的情况下。

大多数转换都基于一系列 SAX 事件。SAX 解析器通常会将 InputStream 或另一个 InputSource 解析为 SAX 事件,然后可以将其馈送到 Transformer。可以使用 SAXResult 代替将 Transformer 输出到文件、字符串或其他此类结果。SAXResult 接受一个 ContentHandler,它可以将这些 SAX 事件直接传递给另一个 Transformer 等。

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

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.
于 2009-08-23T22:38:38.440 回答
3

相关问题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));
于 2013-03-01T16:10:46.073 回答
2

你最好的选择是坚持使用 DOM,因为 XSLT 处理器无论如何都必须构建一棵树 - 流式传输只是非常有限的转换类别的一种选择,几乎没有处理器可以自动找出并切换到仅流式实现;否则他们只会读取输入并构建树。

于 2009-08-21T17:22:43.563 回答