Efficiente gasdotto XSLT in Java (o il reindirizzamento Risultati a origini)
Domanda
Ho una serie di fogli di stile XSL 2.0 che alimentano l'uno nell'altro, cioè l'uscita del foglio di stile A alimenta B alimenta C.
Qual è il modo più efficace di fare questo? La domanda è riformulato:. Come si può in modo efficiente l'uscita di una trasformazione in un altro
Ecco il mio primo tentativo:
@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);
}
Come si può vedere, sto usando un DOM di sedersi tra le trasformazioni, e anche se è conveniente, è non ottimale prestazioni saggio.
C'è un modo semplice per instradare a dire, percorso un SAXResult ad un SAXSource? Una soluzione StAX sarebbe un'altra opzione.
Sono consapevole di progetti come XProc , che è molto bello se non avete dato un'occhiata a ancora, ma non ho voglia di investire in un quadro complesso.
Soluzione
Ho trovato questo: # 3. Concatenamento Trasformazioni che mostra due modi di utilizzare la TransformerFactory a trasformazioni catena, aventi i risultati di uno trasformano mangimi successivo trasformazione e infine uscita sistema fuori. Questo evita la necessità di una serializzazione intermedio String, file e così via tra le trasforma.
Quando multipla, successiva trasformazioni sono necessari al stesso documento XML, essere sicuri di evitare le operazioni di analisi non necessarie. io frequente imbattersi in codice che trasforma una stringa in un'altra stringa, poi trasforma la stringa ad ancora un'altra stringa. Non solo questo è lento, ma si può consumare un significativo quantità di memoria, come pure, specialmente Se le stringhe intermedi non sono permesso di essere garbage collection.
La maggior parte delle trasformazioni si basano su un serie di eventi SAX. Un parser SAX tipicamente analizzare un InputStream o un'altra InputSource in eventi SAX, che possono poi essere alimentato ad un Trasformatore. Invece di avere la uscita del trasformatore in un file, String, o un altro tale risultato, un SAXResult può essere utilizzato. A SAXResult accetta un ContentHandler, che può passare questi eventi SAX direttamente al un altro trasformatore, ecc.
Qui è un approccio, e quello che ho di solito preferiscono in quanto fornisce più flessibilità per vari input e sorgenti di uscita. Inoltre lo rende abbastanza facile creare una trasformazione catena dinamicamente e con una variabile numero di trasformazioni.
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.
Altri suggerimenti
La cosa migliore è quella di attenersi a DOM come si sta facendo, perché un processore XSLT avrebbe dovuto costruire un albero in ogni caso - lo streaming è solo un'opzione per la categoria molto limitata di trasformazioni, e pochi eventuali processori possono capirlo automaticamente e passare a un'implementazione di streaming sola; altrimenti basta leggere l'input e costruire l'albero.
pipeline efficiente a XSLT, con params, in Java chiarito su parametri corretti passaggio di tale catena trasformatore.
E ha anche dato un suggerimento su soluzione leggermente più corta senza terzo trasformatore:
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));