Effiziente XSLT-Pipeline in Java (oder Umleiten Ergebnisse zu Quellen)
Frage
ich eine Reihe von XSL 2.0 Sheets haben, die ineinander zuzuführen, das heißt das Ausgangssignal des A Sheet speist B C speist.
Was ist der effizienteste Weg, dies zu tun? Die Frage neu formuliert ist. Wie kann man effizient zu routen der Ausgang einer Transformation in ein anderes
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, um den Weg zu sagen, route ein SAXResult zu einem SAXSource? Eine StAX Lösung wäre eine weitere Option.
Ich bin mir dessen bewusst Projekte wie XProc , was sehr cool ist, wenn man nicht einen Blick auf noch getroffen haben, aber ich wollte nicht in einem ganzen Rahmen investieren.
Lösung
Ich fand dies: #3. Transformations Chaining dass zwei Möglichkeiten zeigt die verwenden TransformerFactory , um Ketten Transformationen, wobei die Ergebnisse einer Vorschub verwandeln die nächste Transformation und dann schließlich Ausgabe-System aus. Dadurch entfällt die Notwendigkeit für eine Zwischen Serialisierung String, Datei usw. zwischen Transformationen.
Wenn mehrere aufeinanderfolgende Transformationen werden auf die erforderliche gleiches XML-Dokument, sollten Sie vermeiden unnötige Parsing-Operationen. ich häufig laufen in Code, verwandelt einen String an einen anderen String, dann verwandelt sich diese String noch ein anderer String. Dies ist nicht nur langsam, aber es kann eine erhebliche verbrauchen Speichermenge als auch vor allem wenn die Zwischen Strings sind nicht erlaubt Müll gesammelt werden.
sind die meisten Transformationen basiert auf einem System Serie von SAX Ereignisse. Ein SAX-Parser wird in der Regel einen Inputstream analysieren oder eine andere Input in SAX Ereignisse, die dann auf ein zugeführt werden Transformator. Anstatt die mit Transformator Ausgabe in eine Datei, String, oder ein anderes solches Ergebnis, ein SAXResult kann stattdessen verwendet werden. Ein SAXResult akzeptiert ein Content, die kann passieren diese SAX Ereignisse direkt an ein weiterer Transformator, etc.
Hier ist ein Ansatz, und die, die ich in der Regel bevorzugen, da es mehr bietet Flexibilität für verschiedene Ein- und Ausgabequellen. Es macht es auch ziemlich einfach, eine Transformation zu erstellen Kette dynamisch und mit einem variablen Anzahl der Transformationen.
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.
Andere Tipps
Ihre beste Wette ist, um DOM zu bleiben, wie Sie tun, weil ein XSLT-Prozessor ohnehin einen Baum bauen würde - Streaming ist nur eine Option für sehr begrenzte Gruppe von Transformationen, und wenige, wenn irgendwelche Prozessoren können es herausfinden automatisch und wechseln Sie zu einer Streaming-only Umsetzung; sie lesen nur die Eingabe sonst und den Baum zu bauen.
Verwandte Frage Efficient XSLT-Pipeline, mit params, in Java korrekten Parameter geklärt auf solchen Transformator Kette übergeben.
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));