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

时间:2009-08-21 14:47:44

标签: java xslt dom sax pipeline

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

3 个答案:

答案 0 :(得分:23)

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

  

多次,连续   转换是必需的   相同的XML文档,一定要避免   不必要的解析操作。一世   经常遇到代码   将String转换为另一个String,   然后将该String转换为   另一个String。这不仅很慢,   但它可以消耗很大的   特别是,记忆的数量   如果中间字符串不是   允许垃圾收集。

     

大多数转换都是基于a   一系列SAX事件。 SAX解析器   通常会解析InputStream或   另一个进入SAX事件的InputSource,   然后可以喂给一个   变压器。而不是拥有   Transformer输出到File,String,   或另一个这样的结果,SAXResult   可以用来代替。 SAXResult   接受ContentHandler,可以   将这些SAX事件直接传递给   另一个变形金刚等

     

这是一种方法,一种方法   通常更喜欢,因为它提供更多   灵活的各种输入和   输出源。它也成功了   相当容易创建转型   链动态地和变量链   转化次数。

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.

答案 1 :(得分:2)

你最好的选择是坚持你正在做的DOM,因为XSLT处理器无论如何都必须构建一个树 - 流只是非常有限的转换类型的一个选项,并且很少有任何处理器可以解决它自动切换到仅限流媒体的实现;否则他们只是阅读输入并构建树。

答案 2 :(得分:2)

相关问题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));