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.

De esta manera declaramos las librerías:

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();
	}
}

Posted in

One response to “Crear documentos PDF con Java”

  1. Yunuen Lucatero
    Posted May 3, 2011 at 6:54 pm | Permalink

    Hola!
    Tu Post me sirvió mucho, solo que tengo un problema.
    No sabes qué versión de FOP contiene la clase org.apache.fop.apps.Driver,
    porque en la nueva versión no se encuentra ese archivo.

    Gracias!

Leave a Reply