2009-08-21 3 views
19

ich eine Reihe von XSL 2.0 Stylesheets, die ineinander füttern, dh die Ausgabe von Sheet A B-Feeds Feeds C.Effiziente XSLT-Pipeline in Java (oder Umleiten Ergebnisse zu Quellen)

Was ist der effizienteste Weg, das zu tun? Die umformulierte Frage lautet: Wie kann man die Ausgabe einer Transformation effizient in eine andere umlenken?

Hier ist mein erster Versuch:

@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); 
} 

Wie Sie sehen können, bin ich ein DOM zwischen Transformationen zu sitzen, und obwohl es bequem ist, es ist nicht optimale Leistung klug.

Gibt es eine einfache Möglichkeit zu routen, ein SAXResult an eine SAXSource zu leiten? Eine StAX-Lösung wäre eine weitere Option.

Ich kenne Projekte wie XProc, die sehr cool ist, wenn Sie noch nicht gesehen haben, aber ich wollte nicht in ein ganzes Framework investieren.

+3

"für (Transformator autobot: autobots) {" Priceless :-) –

Antwort

23

Ich fand diese: #3. Chaining Transformations, die zwei Möglichkeiten zeigen den TransformerFactory Ketten Transformationen zu verwenden, die Ergebnisse einer Feed-System der nächsten Transformation und dann schließlich Ausgabe aus transformieren müssen. Dies vermeidet die Notwendigkeit einer intermediären Serialisierung zu String, Datei usw. zwischen Transformationen.

Wenn mehrere aufeinanderfolgende Transformationen auf die Dokument gleichen XML benötigt werden, stellen Sie sicher, unnötige Parsing-Operationen zu vermeiden. I häufig in Code ausgeführt, wandelt einen String in einen anderen String, wandelt dann diesen String in noch anderen String. Dies ist nicht nur langsam, , aber es kann eine erhebliche Menge an Speicher auch verbrauchen, insbesondere , wenn die Zwischen-Strings nicht zulässig sind, um Müll gesammelt werden. Die meisten Transformationen basieren auf einer Reihe von SAX-Ereignissen der -Reihe. Ein SAX-Parser parst normalerweise einen InputStream oder eine andere InputSource in SAX-Events, , die dann in einen Transformer eingespeist werden können. Anstatt die Transformer-Ausgabe in eine Datei, String, oder ein anderes solches Ergebnis zu haben, kann stattdessen ein SAXResult verwendet werden. Ein SAXResult akzeptiert eine Content, die diese SAX Ereignisse direkt an einen anderen Transformator usw.

Hier ist ein Ansatz, und die, die ich in der Regel bevorzugen, da es mehr Flexibilität für verschiedene Ein- und liefert Ausgang passieren kann Quellen. Es macht es auch relativ einfach, eine Transformation Kette dynamisch und mit einer Variablen Anzahl der Transformationen zu erstellen.

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. 
+3

Großartig, das sieht genau nach dem aus, was ich suche. Nur neugierig - was hast du gesucht, um das zu finden? Mein Google-Foo muss eingerostet sein. –

+2

Eigentlich hat mich deine Frage an Code erinnert, den ich vor einiger Zeit implementiert habe. Ich wusste, dass es eine saxtransformerfactory verwendet, also habe ich gegoogelt: "saxtransformerfactory chain transformationen". Es scheint merkwürdig schwer zu finden, wenn man bedenkt, wie viel Code/Logik/Probleme es bei der Pipeline-Transformation speichert. –

+0

Laut http://www.onjava.com/pub/a/onjava/excerpt/java_xslt_ch5/?page=6 kann man testen, ob transFact.getFeature (SAXTransformerFactory.FEATURE) in der Lage ist, sicher nach SAXTransformerFactory zu casten. –

2

Am besten bleiben Sie bei DOM, weil ein XSLT-Prozessor sowieso einen Baum erstellen müsste - Streaming ist nur eine Option für eine sehr begrenzte Kategorie von Transformationen, und nur wenige Prozessoren können es berechnen automatisch aus und wechseln zu einer reinen Streaming-Implementierung; ansonsten lesen sie nur die Eingabe und bauen den Baum.

+1

Dies ist nicht korrekt. Verhalten ist implementierungsabhängig. Die Java W3C DOM-Implementierung ist sehr ineffizient und die meisten Implementierungen verwenden eine effizientere interne Repräsentation dieses DOM. Die angenommene Antwort * verbessert * also die Leistung gegenüber "bleib bei DOM". – rmuller

2

Verwandte Frage Efficient XSLT pipeline, with params, in Java auf korrekten Parameter geklärt solchen Transformator Kette vorbei.

Und es gab auch einen Hinweis auf etwas kürzere Lösung ohne dritten Transformator:

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)); 
Verwandte Themen