Export table as a PDF file in ADF

You have learned how to export table as Excel and XML files, now you will learn how to export table as a PDF file using the Apache FOP. Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL formatting objects (XSL-FO) and an output independent formatter. Output formats currently supported include PDF, PS, PCL, AFP, XML, Print, AWT, PNG, RTF and TXT.

Download the sample application: ADFPDFApp.zip.

First of all, we need to transform the data of employees to XML.
To achieve it, look at this blog post: Export table as XML file in ADF.

With some changes, we will be able to export table as a PDF file.
Go to ViewController Project Properties and add Apache FOP libs.

export-table-as-a-pdf-file-in-adf1

export-table-as-a-pdf-file-in-adf2

Create a PDF Template (XML file) under Web Content/stylesheets folder and name it as employeesfo.xsl.
Copy the following code inside employeesfo.xsl file.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1" exclude-result-prefixes="fo" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
  <xsl:output method="xml" version="1.0" omit-xml-declaration="no" indent="yes"/>
  <!--=========================-->
  <!--root element: Employees-->
  <!--=========================-->
  <xsl:template match="Employees">
    <fo:root>
      <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">Employees</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="4cm"/>
              <fo:table-header text-align="center" background-color="silver" font-weight="bold">
                <fo:table-row>
                  <fo:table-cell padding="1mm" border-style="solid">
                    <fo:block>ID</fo:block>
                  </fo:table-cell>
                  <fo:table-cell padding="1mm" border-style="solid">
                    <fo:block>First Name</fo:block>
                  </fo:table-cell>
                  <fo:table-cell padding="1mm" border-style="solid">
                    <fo:block>Last Name</fo:block>
                  </fo:table-cell>
                  <fo:table-cell padding="1mm" border-style="solid">
                    <fo:block>Job Id</fo:block>
                  </fo:table-cell>
                </fo:table-row>
              </fo:table-header>
              <fo:table-body>
                <xsl:apply-templates select="Employee"/>
              </fo:table-body>
            </fo:table>
          </fo:block>
        </fo:flow>
      </fo:page-sequence>
    </fo:root>
  </xsl:template>
  <!--=========================-->
  <!--child element: Employee-->
  <!--=========================-->
  <xsl:template match="Employee">
    <fo:table-row>
      <fo:table-cell>
        <fo:block>
          <xsl:value-of select="EmployeeId"/>
        </fo:block>
      </fo:table-cell>
      <fo:table-cell>
        <fo:block>
          <xsl:value-of select="FirstName"/>
        </fo:block>
      </fo:table-cell>
      <fo:table-cell>
        <fo:block>
          <xsl:value-of select="LastName"/>
        </fo:block>
      </fo:table-cell>
      <fo:table-cell>
        <fo:block>
          <xsl:value-of select="JobId"/>
        </fo:block>
      </fo:table-cell>
    </fo:table-row>
  </xsl:template>
</xsl:stylesheet>

export-table-as-a-pdf-file-in-adf3

Add two methods inside EmployeesBean class to get the PDF template and generate the PDF file.
Open the EmployeesBean class and add the following code:

private static String TEMPLATE_PDF_EMPLOYEES = "stylesheets/employeesfo.xsl";

private static FopFactory fopFactory = FopFactory.newInstance();

private static TransformerFactory tFactory = TransformerFactory.newInstance();

private InputStream getTemplate(String template) {
  FacesContext facesContext = FacesContext.getCurrentInstance();
  return facesContext.getExternalContext().getResourceAsStream(template);
}

private void convertDOM2PDF(Node xml, InputStream template, OutputStream out) {
  try {
    // configure foUserAgent as desired
    FOUserAgent foUserAgent = fopFactory.newFOUserAgent();

    try {
      // Construct fop with desired output format and output stream
      Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);

      // Setup Identity Transformer
      TransformerFactory factory = TransformerFactory.newInstance();
      Transformer transformer = factory.newTransformer(new StreamSource(template));

      // Setup input for XSLT transformation
      Source src = new DOMSource(xml);

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

      // Start XSLT transformation and FOP processing
      transformer.transform(src, res);
    } finally {
      out.close();
    }

  } catch (Exception e) {
    e.printStackTrace(System.err);
  }
}

export-table-as-a-pdf-file-in-adf4

Rename the exportSelectedRowsToXML method to exportSelectedRowsToPDF.
Remove try-catch block from exportSelectedRowsToPDF method and add the following code:

try {
  convertDOM2PDF(rs.writeXML(0, XMLInterface.XML_OPT_ALL_ROWS), getTemplate(TEMPLATE_PDF_EMPLOYEES), outputStream);
} catch (Exception e) {
  e.printStackTrace();
}

export-table-as-a-pdf-file-in-adf5

Rename the exportAllRowsToXML method to exportAllRowsToPDF.
Remove try-catch block from exportAllRowsToPDF method and add the following code:

try {
  convertDOM2PDF(vo.writeXML(0, XMLInterface.XML_OPT_ALL_ROWS), getTemplate(TEMPLATE_PDF_EMPLOYEES), outputStream);
} catch (Exception e) {
  e.printStackTrace();
}

export-table-as-a-pdf-file-in-adf6

The empView.jsf file contains an employees table and two buttons to export rows as PDF file.
Go to source tab and change the properties of af:fileDownloadActionListener tags.

export-table-as-a-pdf-file-in-adf7

Now, when you run the application, you can export all rows as a PDF File.

export-table-as-a-pdf-file-in-adf8

You can export only the selected rows as a PDF File too.

export-table-as-a-pdf-file-in-adf9

Waslley Souza

Author: Waslley Souza

Consultor Oracle com foco em tecnologias Oracle Fusion Middleware e SOA. Certificado Oracle WebCenter Portal, Oracle ADF e Java.

4 thoughts on “Export table as a PDF file in ADF”

    1. Hi Eric!
      Open the EmployeesBean class and change MimeConstants.MIME_PDF to MimeConstants.MIME_RTF.
      Open the empView.jsf page and change the contentType property to application/rtf and filename property to .rtf
      You don’t need to change the template file.

  1. Hello,

    Your blog is very good however I feel you need to point out a very subtle point due to several hours of frustration. I found you should highlight the ‘Root’ issue. Which is a bridge between each of your blogs. In your Print to XML blog on this subject at the very end you rename in the view object the Root and Children Root in the custom properties.

    I refer to XML_ELEMENT and XML_ROW_ELEMENT, then I also found on the primary key of the table attributes which maps to XML_ELEMENT under custom properties of the attribute EmployeeId. These two little things are critical to making this work, but the naming is ‘Employees’ (plural) and ‘Employee’ (singular) in the ’employeefo.xsl’ template which is understandable due to the fact we are talking about a row or many rows. But, these are only found in the images you posted on the blog.

    In the employeesfo.xsl template: the line as the Root as defined in the view object under custom properties. And the line <xsl:apply-template select='Employee' (singular) is a load of the template before the child element followed by the line which defines the template for the children.

    Hope this helps people.

Leave a Reply

Your email address will not be published. Required fields are marked *