Crear documentos PDF con Java
Utilizaremos el proyecto open source Apache FOP (Formatting Objects Processor) que nos da una serie de funciones para convertir un documento XML a un documento PDF, PS, Texto entre otros.
Este proyecto toma un archivo XSL-FO y lo convierte en formato PDF, por lo que habrá que convertir primero nuestro archivo XML a XSL-FO antes de convertirlo a un documento PDF.
Archivos XML y XSLT
Vamos a crear dos archivos, el primero será en formato xml. En este archivo se guardarán los datos de nuestro documento PDF.
Archivo glossary.xml
<?xml version="1.0"?> <glossary> <term-entry> <term>basic-link</term> <definition>The fo:basic-link is used for representing the start resource of a simple link.</definition> </term-entry> <term-entry> <term>bidi-override</term> <definition>The fo:bidi-override inline formatting object is used where it is necessary to override the default Unicode-bidirectionality algorithm direction for different (or nested) inline scripts in mixed-language documents.</definition> </term-entry> <term-entry> <term>block</term> <definition>The fo:block formatting object is commonly used for formatting paragraphs, titles, headlines, figure and table captions, etc.</definition> </term-entry>
Archivo glossary.xslt
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0"> <xsl:template match="glossary"> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> <fo:layout-master-set> <fo:simple-page-master master-name="all" page-height="11.5in" page-width="8.5in" margin-top="1in" margin-bottom="1in" margin-left="0.75in" margin-right="0.75in"> <fo:region-body margin-top="1in" margin-bottom="0.75in"/> <fo:region-before extent="0.75in"/> <fo:region-after extent="0.5in"/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="all" format="i"> <fo:static-content flow-name="xsl-region-before"> <fo:block text-align="start" font-size="10pt" font-family="serif" line-height="1em + 2pt"> <fo:retrieve-marker retrieve-class-name="term" retrieve-boundary="page" retrieve-position="first-starting-within-page"/> <fo:leader leader-alignment="reference-area" leader-pattern="dots" leader-length="4in"/> <fo:retrieve-marker retrieve-class-name="term" retrieve-boundary="page" retrieve-position="last-ending-within-page"/> </fo:block> </fo:static-content> <fo:static-content flow-name="xsl-region-after"> <fo:block text-align="start" font-size="10pt" font-family="serif" line-height="1em + 2pt"> Page (<fo:page-number/>) </fo:block> </fo:static-content> <fo:flow flow-name="xsl-region-body"> <xsl:apply-templates select="term-entry"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="term-entry"> <fo:block text-align="start" font-size="12pt" font-family="sans-serif"> <xsl:apply-templates select="term"/> <xsl:apply-templates select="definition"/> </fo:block> </xsl:template> <xsl:template match="term"> <fo:block color="blue" space-before.optimum="3pt"> <fo:marker marker-class-name="term"><xsl:value-of select="."/> </fo:marker> <xsl:value-of select="."/> </fo:block> </xsl:template> <xsl:template match="definition"> <fo:block text-align="start" start-indent="2em"> <xsl:value-of select="."/> </fo:block> </xsl:template> </xsl:stylesheet>
Convertir documento XML a XSL-FO
El proyecto Apache FOP incluye las librerías: FOP, Logger, Graphics, Xerces, XML y XSLT.
| Archivo JAR | Descripción |
|---|---|
| fop.jar | FOP API |
| avalon-framework-cvs-20020806.jar | Logger |
| batik.jar | Graphics |
| xercesImpl-2.2.1.jar | Xerces API |
| xml-apis.jar | XML API |
| xalan-2.4.1.jar | XSLT API |
import org.apache.avalon.framework.logger.*; import org.apache.fop.apps.*; import org.xml.sax.InputSource; import org.xml.sax.*; import org.w3c.dom.*;
public void generarXSLFO(File archivoXML, File archivoXSLT)
{
try {
System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document documento = builder.parse(archivoXML);
TransformerFactory tFactory = TransformerFactory.newInstance();
StreamSource stylesource = new StreamSource(archivoXSLT);
Transformer transformer = tFactory.newTransformer(stylesource);
DOMSource source = new DOMSource(documento);
StreamResult result = new StreamResult("glossary.fo");
transformer.transform(source, result);
} catch (TransformerConfigurationException e) {
System.out.println(e.getMessage());
} catch (TransformerException e) {
System.out.println(e.getMessage());
} catch (SAXException e) {
System.out.println(e.getMessage());
} catch (ParserConfigurationException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
}
}Generar documento PDF
Una vez generados el archivo glossary.fo, podemos generar nuestro documento PDF.
public void generarPDF()
{
try {
Driver driver = new Driver();
Logger logger = new ConsoleLogger(ConsoleLogger.LEVEL_INFO);
driver.setLogger(logger);
org.apache.fop.messaging.MessageHandler.setScreenLogger(logger);
driver.setRenderer(Driver.RENDER_PDF);
InputStream input = new FileInputStream(new File("glossary.fo"));
driver.setInputSource(new InputSource(input));
OutputStream output = new FileOutputStream(new File("glossary.pdf"));
driver.setOutputStream(output);
driver.run();
output.flush();
output.close();
} catch (IOException e) {
System.out.println(e.getMessage());
} catch (org.apache.fop.apps.FOPException e) {
System.out.println(e.getMessage());
}
}Código Completo
Código del archivo ConvertirPDF.java
package org.luisalberto.xml2pdf;
import java.io.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.apache.avalon.framework.logger.*;
import org.apache.fop.apps.*;
import org.xml.sax.InputSource;
import org.xml.sax.*;
import org.w3c.dom.*;
public class ConvertirPDF
{
public void generarXSLFO(File archivoXML, File archivoXSLT)
{
try {
System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document documento = builder.parse(archivoXML);
TransformerFactory tFactory = TransformerFactory.newInstance();
StreamSource stylesource = new StreamSource(archivoXSLT);
Transformer transformer = tFactory.newTransformer(stylesource);
DOMSource source = new DOMSource(documento);
StreamResult result = new StreamResult("glossary.fo");
transformer.transform(source, result);
} catch (TransformerConfigurationException e) {
System.out.println(e.getMessage());
} catch (TransformerException e) {
System.out.println(e.getMessage());
} catch (SAXException e) {
System.out.println(e.getMessage());
} catch (ParserConfigurationException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
public void generarPDF()
{
try {
Driver driver = new Driver();
Logger logger = new ConsoleLogger(ConsoleLogger.LEVEL_INFO);
driver.setLogger(logger);
org.apache.fop.messaging.MessageHandler.setScreenLogger(logger);
driver.setRenderer(Driver.RENDER_PDF);
InputStream input = new FileInputStream(new File("glossary.fo"));
driver.setInputSource(new InputSource(input));
OutputStream output = new FileOutputStream(new File("glossary.pdf"));
driver.setOutputStream(output);
driver.run();
output.flush();
output.close();
} catch (IOException e) {
} catch (org.apache.fop.apps.FOPException e) {
System.out.println(e.getMessage());
}
}
}Código del archivo Test.java
package org.luisalberto.xml2pdf;
import java.io.*;
import org.luisalberto.xml2pdf.ConvertirPDF;
public class Test
{
public static void main(String[] argv)
{
ConvertirPDF xmlPDF= new ConvertirPDF();
File archivoXML = new File("glossary.xml");
File archivoXSLT = new File("glossary.xslt");
xmlPDF.generarXSLFO(archivoXML, archivoXSLT);
xmlPDF.generarPDF();
}
}
Hola,
He intentado ejecutar tu ejemplo pero no me compila.
Estoy usando la versión 0.95 de FOP y no me compila la clase Driver.
Ok, resuelto con la versión 0.20.5 en lugar de la 0.95
Que tal Manuel, que bueno que funcionó mi ejemplo, pronto pondré la liga para descargar el ejemplo.
Hola
Estoy usando java+xsl+xml para generar ficheros HTML y espero que puedas responder a mi pregunta (aunque no genere pdf que es el tema del post).
Al compilar Xalan para la generacion de los HTML yo le puedo pasar parametros del siguiente modo (esto es el comando que meto en MSDOS)
C:\xalan-j_2_7_1>java -classpath “xalan.jar;serializer.j
ar;xml-apis.jar;xercesImpl.jar” org.apache.xalan.xslt.Process -IN ficheroxml.xml -XSL ficheroxsl.xsl -OUT salida.html -PARAM nombreparametro valor
¿Como puedo pasar parametros usando el codigo que pones aqui que es muy similar al que uso yo?
He probado añadiendolo detras de los nombres en las siguientes lineas pero da error o genera ficheros lalamdos “glossary.fo -PARAM nombreparametro valor”
Document documento = builder.parse(archivoXML)+ “-PARAM nombreparametro valor”;
StreamSource stylesource = new StreamSource(archivoXSLT)+”-PARAM nombreparametro valor”;
StreamResult result = new StreamResult(“glossary.fo”)+”-PARAM nombreparametro valor”;3
Espero que me peudas ayudar.
Saludos
Hola gracias por la explicacion esta bien entendible.
Tengo el mismo problema q Manuel, estoy usando la version 0.95 y la clase Driver no la reconoce, no estoy segura a q libreria corresponde, si me pudiese ayudar, o directamente cambio todos los jar por los de la version 0.20
Gracias
Que tal Marcela, este ejemplo funciona muy bien con la versión 0.20. Por otro lado voy a modificar esta publicación ya que al parecer las versiones no son compatibles. Claro que, necesito analizar la última versión estable que es 0.95.
Gracias por tus comentarios