XSLT tubería eficiente en Java (o redirigir los resultados a Fuentes)
Pregunta
I tienen una serie de XSL 2.0 hojas de estilo que se alimentan entre sí, es decir, la salida de hoja de estilo A alimenta B alimenta C.
¿Cuál es la forma más eficiente de hacer esto? La pregunta es reformulado:. ¿Cómo puede una ruta eficiente la salida de una transformación en otro
Aquí está mi primer intento:
@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);
}
Como se puede ver, estoy usando un DOM para sentarse en medio de transformaciones, y aunque es conveniente, es no óptimo rendimiento inteligente.
¿Hay alguna forma fácil de ruta decir, una ruta SAXResult a un SAXSource? Una solución StAX sería otra opción.
Estoy al tanto de proyectos como XProc , que es muy bien si usted no ha echado un vistazo a, sin embargo, pero yo no quería invertir en su conjunto un marco.
Solución
He encontrado esto: # 3. Encadenamiento de Transformaciones que muestra dos formas de usar el TransformerFactory a las transformaciones de la cadena, que tiene los resultados de uno transforman alimentación la siguiente transformada y, finalmente, la salida a sistema fuera. Esto evita la necesidad de una serialización intermedio de cadena, archivo, etc., entre las transformadas.
Cuando múltiple, sucesiva transformaciones son necesarios para la mismo documento XML, asegúrese de evitar las operaciones de análisis innecesarios. yo con frecuencia ejecutar en código que transforma una cadena a otra cadena, a continuación, se transforma a esa cadena aún otra cadena. Esto no sólo es lento, pero puede consumir una significativa cantidad de memoria y, sobre todo Si las cadenas intermedias no son permitido ser basura recogida.
La mayoría de las transformaciones se basan en una serie de eventos SAX. Un analizador SAX típicamente analizar un InputStream o otra InputSource en eventos SAX, que luego pueden ser alimentados a una Transformador. En lugar de tener la transformador de salida a un archivo, cadena, u otro tal resultado, un SAXResult se puede utilizar en su lugar. Un SAXResult acepta un ContentHandler, que puede pasar estos eventos SAX directamente a otro transformador, etc.
Este es un enfoque, y la que yo por lo general prefieren, ya que proporciona más flexibilidad para diversos entrada y fuentes de salida. También hace que sea bastante fácil para crear una transformación cadena dinámicamente y con una variable número de transformaciones.
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.
Otros consejos
Lo mejor es atenerse a DOM como que estás haciendo, porque un procesador XSLT tendría que construir un árbol de todos modos - streaming es sólo una opción para categoría muy limitada de transformaciones, y pocos o ninguno de los procesadores pueden averiguarlo automáticamente y cambiar a una aplicación de streaming de sólo; de lo contrario se acaba de leer la entrada y construir el árbol.
tubería XSLT eficiente, con parametros, en Java esclarecido sobre parámetros correctos que pasan a dicha cadena transformador.
Y también dio una pista en la solución un poco más corto y sin tercer transformador:
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));