Creare PDF da un XML con Apache FOP 1.1

DOMANDA:

Come si crea un PDF da un file XML?



RISPOSTA:

E' possibile creare un PDF a partire da un XML con Apache FOP 1.1, ultima versione attualmente disponibile. E' indispensabile sapere che per la trasformazione è necessario un file "intermedio" .xsl utilizzato come template (modello) in cui vengono conservate le informazioni di impaginazione.

Come al solito, guardiamo con degli esempi ad hoc ogni singolo step anche se, in questo post, si da per scontata una conoscenza basilare di xml ed xsl.

La seguente classe Xml2Pdf trasforma l'XML in PDF grazie alle informazioni contenute nel .xsl:
package fop;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;

public class Xml2Pdf {
  public static void main(String[] args) throws IOException {

    File xmlIn = new File("C:\\rubrica.xml");
    File xslt = new File("C:\\rubrica.xsl");
    File pdfOut = new File("C:\\rubrica.pdf");

    // Setup output
    OutputStream out = new java.io.FileOutputStream(pdfOut);
    out = new java.io.BufferedOutputStream(out);

    try {
      FopFactory fopFactory = FopFactory.newInstance();
      FOUserAgent foUserAgent = fopFactory.newFOUserAgent();

      // Costruisco il fop con l'output desiderato
      Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);

      // Setup XSLT
      TransformerFactory factory = TransformerFactory.newInstance();
      Transformer transformer = factory.newTransformer(new StreamSource(new InputStreamReader(new FileInputStream(xslt), "UTF-8")));
      transformer.setOutputProperty("encoding", "UTF-8"); // Setto l'encoding di output
      transformer.setParameter("versionParam", "2.0"); // Setto il valore di versionParam nello stylesheet

      Source src = new StreamSource(xmlIn); // Setup input per la trasformazione XSLT 

      Result res = new SAXResult(fop.getDefaultHandler());
   
      transformer.transform(src, res); // Inizio XSLT transformation XSLT e FOP processing

    } catch (Exception e) {
       e.printStackTrace(System.err);
       System.exit(-1);
    } finally {
       out.close();
    }
  }
}
Per il corretto funzionamento della classe è necessario scaricare ed aggiungere al classpath/buildpath alcune librerie Apache FOP versione 1.1 (10,5 MB). Il file .rar contiene tutti i jar necessari elencati di seguito:
  • fop.jar
  • avalon-framework-4.2.0.jar
  • batik-all-1.7.jar
  • commons-io-1.3.1.jar
  • commons-logging-1.0.4.jar
  • serializer-2.7.0.jar
  • xalan-2.7.0.jar
  • xercesImpl-2.7.1.jar
  • xml-apis-1.3.04.jar
  • xml-apis-ext-1.3.04.jar
  • xmlgraphics-commons-1.5.jar


Il file rubrica.xsl:
<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" exclude-result-prefixes="fo">
<xsl:output method="xml" version="1.0" omit-xml-declaration="no" indent="yes"/>
<xsl:param name="versionParam" select="'1.0'"/>

<!-- definizione di rubrica -->
<xsl:template match="rubrica">
  <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <fo:layout-master-set>
      <fo:simple-page-master master-name="simpleA4" page-height="29.7cm" page-width="21cm" margin-top="2cm" margin-bottom="2cm" margin-left="2cm" margin-right="2cm">
        <fo:region-body/>
      </fo:simple-page-master>
    </fo:layout-master-set>

    <fo:page-sequence master-reference="simpleA4">
      <fo:flow flow-name="xsl-region-body">
        <fo:block font-size="16pt" font-weight="bold" space-after="5mm">Titolo: <xsl:value-of select="titolo"/>
        </fo:block>
        <fo:block font-size="12pt" space-after="5mm">Version <xsl:value-of select="$versionParam"/>
        </fo:block>
        <fo:block font-size="10pt">
          <fo:table table-layout="fixed" width="100%" border-collapse="separate">
            <fo:table-column column-width="4cm"/>
            <fo:table-column column-width="4cm"/>
            <fo:table-column column-width="4cm"/>
            <fo:table-column column-width="5cm"/>
            <fo:table-body>
                <xsl:apply-templates select="persona"/>
            </fo:table-body>
          </fo:table>
        </fo:block>
      </fo:flow>
    </fo:page-sequence>
  </fo:root>
</xsl:template>

<!-- definizione dell'elemento PERSONA -->
<xsl:template match="persona">
  <fo:table-row>
    <xsl:if test="professione = 'blogger'">
      <xsl:attribute name="font-weight">bold</xsl:attribute>
    </xsl:if>
    <fo:table-cell>
      <fo:block>
        <xsl:value-of select="nome"/>
      </fo:block>
    </fo:table-cell>
    <fo:table-cell>
      <fo:block>
        <xsl:value-of select="telefono"/>
      </fo:block>
    </fo:table-cell>
    <fo:table-cell>
      <fo:block>
        <xsl:value-of select="professione"/>
      </fo:block>
    </fo:table-cell>
    <fo:table-cell>
      <fo:block>
        <xsl:value-of select="email"/>
      </fo:block>
    </fo:table-cell>
  </fo:table-row>
</xsl:template>

</xsl:stylesheet>

Ed infine il file rubrica.xml:
<?xml version="1.0" encoding="UTF-8"?>
<rubrica>
  <titolo>La mia rubrica</titolo>
  
  <persona>
    <nome>Pippo</nome>
    <telefono>06123456789</telefono>
    <professione>programmatore</professione>
    <email>pippo@unemail.it</email>
  </persona>

  <persona>
    <nome>Fabrizio</nome>
    <telefono>0655555555</telefono> 
    <professione>blogger</professione>
    <email>fabrizio@unemail.it</email>
  </persona>

  <persona>
    <nome>Pluto</nome>
    <telefono>0644444444</telefono>
    <professione>programmatore</professione>
    <email>pluto@unemail.it</email>
  </persona>

  <persona>
    <nome>Paperino</nome>
    <telefono>0633333333</telefono>
    <professione>giornalista</professione>
    <email>paperino@unemail.it</email>
  </persona>

  <persona>
    <nome>Clarabella</nome>
    <telefono>0622222222</telefono>
    <professione>disoccupato</professione>
    <email>clarabella@unemail.it</email>
  </persona>

</rubrica>

Posizionate il file rubrica.xml e rubrica.xsl in C:\ e lanciate la classe Xml2Pdf. Il risultato sarà un file rubrica.pdf con i dati contenuti nel file .xml impaginato secondo i criteri del file .xsl.

Commenti

Post popolari in questo blog

Arrotondamento e troncamento in Java

Eclipse: Shortcuts (scorciatoie) da tastiera

Strutture dati: List, Set, Map

Creare un eseguibile Java