2009-08-21 5 views
19

ho una serie di XSL 2.0 fogli di stile che si alimentano a vicenda, cioè l'uscita del foglio di stile A alimenta B alimenta C.pipeline efficiente a XSLT in Java (o il reindirizzamento Risultati a origini)

Qual è il modo più efficiente di fare questo? La domanda riformulata è: come si può indirizzare in modo efficiente l'output di una trasformazione in un'altra.

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 potete vedere, sto usando un DOM di sedersi tra le trasformazioni, e anche se è conveniente, la sua prestazione non ottimale saggio.

C'è un modo semplice per instradare dire, indirizzare un SAXResult a SAXSource? Una soluzione StAX sarebbe un'altra opzione.

Sono a conoscenza di progetti come XProc, che è molto bello se non si è ancora visto, ma non volevo investire in un intero framework.

+3

"per (Transformer Autobot: Autobots) {" :-) Priceless –

risposta

23

ho trovato questo: #3. Chaining Transformations che mostra due modi di usare il TransformerFactory a trasformazioni catena, aventi i risultati di uno trasformano mangimi successivo trasformazione e infine uscita sistema fuori. Ciò evita la necessità di una serializzazione intermedia su String, file, ecc. Tra le trasformazioni.

Quando più, successive trasformazioni sono necessari per lo stesso documento XML , essere sicuri di evitare operazioni di analisi non necessarie. I esegue frequentemente il codice che trasforma una stringa in un'altra stringa, quindi trasforma quella stringa in ancora un'altra stringa. Non solo è lento, ma può anche consumare una quantità significativa di memoria , in particolare se le stringhe intermedie non sono consentite da raccogliere dati inutili.

La maggior parte delle trasformazioni si basa su una serie di eventi SAX . Un parser SAX analizzerà in genere un InputStream o un altro InputSource in eventi SAX, che può quindi essere inviato a un Trasformatore . Invece di avere l'output del trasformatore su un file, una stringa, o un altro di tali risultati, è possibile utilizzare un SAXResult . Un SAXResult accetta un ContentHandler, che può passare questi eventi SAX direttamente altro trasformatore, ecc

Qui è un approccio, e quello che solito preferiscono quanto fornisce maggiore flessibilità per vario ingresso e uscita fonti. Rende anche abbastanza semplice creare una catena di trasformazione 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. 
+3

Grande, sembra esattamente quello che sto cercando. Solo curioso - cosa hai cercato per trovare quello? Il mio google-foo deve essere arrugginito. –

+2

In realtà, la tua domanda mi ha ricordato un codice che avevo visto implementato qualche tempo fa. Sapevo che utilizzava una saxtransformerfactory, quindi ho cercato su google: "saxtransformerfactory chain transformations". Sembra stranamente difficile da trovare, considerando quanto codice/logica/problema si risparmia quando si vogliono trasformare le trasformazioni. –

+0

In base a http://www.onjava.com/pub/a/onjava/excerpt/java_xslt_ch5/?page=6, è possibile verificare se transFact.getFeature (SAXTransformerFactory.FEATURE) è in grado di trasmettere in sicurezza a SAXTransformerFactory. –

2

La soluzione migliore è quella di attenersi al DOM come si sta facendo, perché un processore XSLT dovrebbe comunque costruire un albero - lo streaming è solo un'opzione per una categoria di trasformazioni molto limitata, e pochi o pochi processori possono capirlo esce automaticamente e passa a un'implementazione solo streaming; altrimenti leggono semplicemente l'input e costruiscono l'albero.

+1

Questo non è corretto. Il comportamento dipende dall'implementazione. L'implementazione del DOM W3C Java è molto inefficiente e la maggior parte delle implementazioni utilizza una rappresentazione interna più efficiente di questo DOM. Quindi la risposta accettata * fa * migliorare le prestazioni rispetto a "stick to DOM". – rmuller

2

questione connessa Efficient XSLT pipeline, with params, in Java chiarito su parametri corretti passaggio di tale catena trasformatore.

Ed è 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));