[Métodos] Generar PDF con xls en Java - Hola Mundo


Apache FOP, de sus siglas en inglés Formatting Objects Processor, el equivalente en español de Procesador de formato de objetos, es un formateador de impresión a través de archivos XSL formatting objects (XMLFO)
Según el mismo framework es capaz de imprimir en muchisimos formatos:
  • PDF, el mas típico y más usado
  • ASCII, PostScript, Direct printer output (PCL), AFP, RTF, Java2D/AWT, menos usuales

Esquema

El esquema básico es se toman tanto el xml como string que genero con xstream, dado en un webservice como desde un archivo, junto al xsl para ser procesados en java a través de apache FOP para generar un pdf(sigla del inglés Portable Document Format, «formato de documento portátil»)



Método

  • Declara 2 objetos FOPFactory y de éste instancia FOUserAgent que servirá para crear el FOP
  • También declara un OutputStream con el path de salida donde se creara el archivo
  • Estos los usa para instancia el objeto FOP junto a una constante que indica que será del tipo PDF
  • Con el path del archivo xsl crea un File y a partir de este un StreamSource que hereda de Source
  • Se crea un TransformerFactory para que junto al xsl instancie un Transformer que procece el xml
  • Declara un objeto Result instanciando un SAXResutl a partir del objeto 'fop'
  • Crea un Source, instanciando StreamSource pero esta vez a partir de un StringReader ya que se trata esta vez de un xml como String.
    Este paso puede cambiar instanciando el streamsource con un objeto file con el path del archivo xml, de igual manera que se hace con xsl.
  • Y el ultimo paso de esta receta mágica, es que el objeto Transformer transforme la fuente del xml junto con el resultado para crear el PDF

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public static String xml = "<valor>Mundo</valor>";
public static String xslPath = "src//dar10//template.xsl";
public static String pdfPath = "src//dar10//resultado.pdf";

public static void main(String...Legendar10) throws IOException, FOPException, TransformerException{
    //Setea el agente para el FOP
    FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
    FOUserAgent foUserAgent = fopFactory.newFOUserAgent();

    OutputStream out = new FileOutputStream(pdfPath);

    try {
        Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);

        // Ubicacion del archivo XSL
        File xsltFile = new File(xslPath);
        Source xslSource = new StreamSource(xsltFile);
        // Transformer a partir del xslt
        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer(xslSource);

        // Resulting SAX events (the generated FO) must be piped through to FOP
        Result res = new SAXResult(fop.getDefaultHandler());

        // Se convierte a 'Source' el xml
        StringReader reader = new StringReader(xml);
        Source xmlSource = new StreamSource(reader);

        // se crea el PDF
        transformer.transform(xmlSource, res);
    } finally {
        out.close();
    }
}

En este caso esta todo contendio en un método main que ejecuta el proceso java. Se crea del proyecto un solo paquete que lo he llamado 'dar10' y los 3 string declarados como estaticos que representan el xml, la ubicacion del xsl, y la ubicacion de destino (que son el mismo paquete dentro del proyecto)

Añadir dependencias en el pom/classpath


1
2
3
4
5
<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.4.10</version>
</dependency>


El XSL (Transformador)


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:fo="http://www.w3.org/1999/XSL/Format">
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="/">
    <fo:root>
      <fo:layout-master-set>
        <fo:simple-page-master master-name="A4-portrait"
              page-height="29.7cm" page-width="21.0cm" margin="2cm">
          <fo:region-body/>
        </fo:simple-page-master>
      </fo:layout-master-set>
      <fo:page-sequence master-reference="A4-portrait">
        <fo:flow flow-name="xsl-region-body">
          <fo:block>
            Hola, <xsl:value-of select="valor"/>!
          </fo:block>
        </fo:flow>
      </fo:page-sequence>
    </fo:root>
  </xsl:template>
</xsl:stylesheet>

El xsl declara en su etiquetas:
  • la version de stylesheet
  • que la fuente de datos será xml
  • que el root del xml empieza en "/" y es a partir de lo que contengan intermente estas etiquetas, aunque nuestro xml solo contiene un tag
  • tmabién declara un layout por defecto y al 'Documento' con las dimensiones de la pagina (A4) y un cuerpo (body)
  • en las etiquetas siguientes declara 'page-sequence' y 'flow' haciendo referencias las anterior mencionadas
  • Y aqui comienza lo bueno, simplemente declara un fo:block, como un contenedor 'div'
  • y buscará con xsl:value-of dentro del root que estemos posicionados ("/") el valor contenido por las etiquetas 'valor'


El resultado:


No hay comentarios:

Publicar un comentario