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 を使用しています。DOM は便利ですが、パフォーマンスに関しては最適ではありません。

SAXResult を SAXSource にルーティングする簡単な方法はありますか? 別の選択肢として、StAX ソリューションがあります。

XProcのようなプロジェクトは知っていますが、まだ見ていないのであれば非常にクールですが、フレームワーク全体に投資するつもりはありませんでした。

4

3 に答える 3

24

私はこれを見つけました:#3。TransformerFactoryを使用して変換をチェーンする 2 つの方法を示す変換のチェーン。1 つの変換の結果を次の変換にフィードし、最終的にシステム出力に出力します。これにより、変換間で文字列やファイルなどへの中間シリアル化が不要になります。

同じ XML ドキュメントに対して複数の連続した変換が必要な場合は、不要な解析操作を避けるようにしてください。String を別の String に変換し、その String をさらに別の String に変換するコードによく出くわします。これは遅いだけでなく、特に中間文字列のガベージ コレクションが許可されていない場合、大量のメモリを消費する可能性があります。

ほとんどの変換は、一連の SAX イベントに基づいています。SAX パーサーは通常、InputStream または別の InputSource を解析して SAX イベントに変換し、それを Transformer に渡すことができます。Transformer の出力をファイル、文字列、または別のそのような結果にするのではなく、代わりに SAXResult を使用できます。SAXResult は、これらの SAX イベントを別の Transformer などに直接渡すことができる ContentHandler を受け入れます。

これが 1 つのアプローチであり、さまざまな入力ソースと出力ソースに対してより柔軟に対応できるため、私が通常好む方法です。また、可変数の変換を使用して、動的に変換チェーンを作成することも非常に簡単になります。

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

関連する質問Javaでのparamsを使用した効率的なXSLTパイプラインは、そのようなトランスフォーマーチェーンに渡される正しいパラメーターについて明確にしました。

また、3 番目のトランスを使用しない、わずかに短いソリューションのヒントも示しました。

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

とにかくXSLTプロセッサはツリーを構築する必要があるため、最善の策はDOMに固執することです.ストリーミングは非常に限られたカテゴリの変換のオプションにすぎず、プロセッサが自動的にそれを理解して切り替えることができる場合はほとんどありません.ストリーミングのみの実装へ。それ以外の場合は、入力を読み取ってツリーを構築するだけです。

于 2009-08-21T17:22:43.563 に答える