Java LaTeX Report – Tutorial

This tutorial explains how to use the JLR (Java LaTeX Report) library by nixo-soft.
To understand the following code, a basic knowledge in LaTeX and Java is required.
Furthermore you’ll probably need realcalc.tex, invoice.sty and invoice.def to execute the sample code.

Requirements: Java Runtime Environment (JRE) 6 Update 20 / Installed or portable LaTeX Distribution (e.g. MiKTeX or MiKTeX Portable)

The tutorial is divided into three parts:



How to create a LaTeX template file

Before we can use the JLR library in our Java project, we have to create a template file in LaTeX.
For this we use the Velocity Template Language (VTL) from Apache.
In our example we keep it simple, but VTL is very powerful and offers lots of possibilities.
Let’s assume that we want to create multiple invoices for different customers (if you need help in creating invoices with Latex, just have a look at CTAN or invoice.pdf).

So, a very simple invoice template could look like:

invoiceTemplate.tex

\documentclass{letter} 
\usepackage{invoice} 
\address{Josh Parker \\
         5650 Webster Ave \\
         West Palm Beach, Florida 33405 \\
         JParker@mail.com} 
\date{31-May-2010} 

\begin{document} 
\begin{letter}{$CustomerName \\ 
               $CustomerStreet \\ 
               $CustomerZip} 
\opening{Invoice no. $Number} 
Dear customer,

... 

\begin{invoice}{Euro}{0} 
\ProjectTitle{Example Project} 

#foreach( $name in $services )
    \Fee{$name[0]} {$name[1]} {1} 
#end 

\end{invoice} 

\closing{Best regards} 
\end{letter} 
\end{document} 

As you can see, there are special tags or patterns ($,#foreach...) with variables, which don’t belong to LaTeX. These are used to indicate variable information (like name, address, date etc.) and will be replaced afterwards.
Look at http://velocity.apache.org/engine/releases/velocity-1.7/user-guide.html to understand the meaning and usage of tags, patterns, variables and Velocity Template Language (VTL). Before you compile the sample code in your LaTeX editor, it’s probably necessary to include realcalc.tex, invoice.sty and invoice.def in your working directory (where your invoiceTemplate.tex lies) - or you can integrate these files into your LaTeX distribution.

Note: Maybe you get some error messages from your LaTeX editor. This is normal – these errors occur because the instruction

\Fee{$name} {$name} {1}

expects a number as second argument (and not the variable name). Later we are going to replace this variable with a number – hence it can be ignored so far.



The PDF file of the invoice template should look like:



invoiceTemplatePDF.



How to use JLR to create a report file

The next step is to start a new Java project and import the JLR library into it.
Now let’s look at some sample code to see how JLR works.

First you have to make a declaration of the template file (e.g. C:\Invoices\invoiceTemplate.tex)
and the output tex files (e.g. C:\Invoices\temp\invoice1.tex and C:\Invoices\temp\invoice2.tex) which you want to create:

File workingDirectory = new File("C:" + File.separator + "Invoices");

File template = new File(workingDirectory.getAbsolutePath() + File.separator + "invoiceTemplate.tex");

File tempDir = new File(workingDirectory.getAbsolutePath() + File.separator + "temp");
if (!tempDir.isDirectory()) {
    tempDir.mkdir();
}
File invoice1 = new File(tempDir.getAbsolutePath() + File.separator + "invoice1.tex");
File invoice2 = new File(tempDir.getAbsolutePath() + File.separator + "invoice2.tex");

Our goal is to fill the template with information. To achieve this, we have to use the
replace() method of JLRConverter, where a key has to correspond to the variables in the template.
The workingDirectory is the directory where the template files are located and it is necessary for JLRConverter.

JLRConverter converter = new JLRConverter(workingDirectory);

converter.replace("Number", "1");
converter.replace("CustomerName", "Ivan Pfeiffer");
converter.replace("CustomerStreet", "Schwarzer Weg 4");
converter.replace("CustomerZip", "13505 Berlin");

ArrayList<ArrayList<String>> services = new ArrayList<ArrayList<String>>();
		
ArrayList<String> subservice1 = new ArrayList<String>();
ArrayList<String> subservice2 = new ArrayList<String>();
ArrayList<String> subservice3 = new ArrayList<String>();
		
subservice1.add("Software");
subservice1.add("50");
subservice2.add("Hardware1");
subservice2.add("500");
subservice3.add("Hardware2");
subservice3.add("850");
		
services.add(subservice1);
services.add(subservice2);
services.add(subservice3);		
		
converter.replace("services", services);

Now we are ready to use JLR and start the replacement procedure:

converter.parse(template, invoice1);

The second invoice (invoice2) is going to be created in an analogous manner.



Let’s sum it up a little:

Main.java

import de.nixosoft.jlr.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

public class Main {

    public static void main(String[] args) {

        File workingDirectory = new File("C:" + File.separator + "Invoices");

        File template = new File(workingDirectory.getAbsolutePath() + File.separator + "invoiceTemplate.tex");

        File tempDir = new File(workingDirectory.getAbsolutePath() + File.separator + "temp");
        if (!tempDir.isDirectory()) {
            tempDir.mkdir();
        }

        File invoice1 = new File(tempDir.getAbsolutePath() + File.separator + "invoice1.tex");
        File invoice2 = new File(tempDir.getAbsolutePath() + File.separator + "invoice2.tex");


        try {
            JLRConverter converter = new JLRConverter(workingDirectory);

            converter.replace("Number", "1");
            converter.replace("CustomerName", "Ivan Pfeiffer");
            converter.replace("CustomerStreet", "Schwarzer Weg 4");
            converter.replace("CustomerZip", "13505 Berlin");

            ArrayList<ArrayList<String>> services = new ArrayList<ArrayList<String>>();
		
            ArrayList<String> subservice1 = new ArrayList<String>();
            ArrayList<String> subservice2 = new ArrayList<String>();
            ArrayList<String> subservice3 = new ArrayList<String>();
		
            subservice1.add("Software");
            subservice1.add("50");
            subservice2.add("Hardware1");
            subservice2.add("500");
            subservice3.add("Hardware2");
            subservice3.add("850");
		
            services.add(subservice1);
            services.add(subservice2);
            services.add(subservice3);		
		
            converter.replace("services", services);
            
            converter.parse(template, invoice1);



            converter.replace("Number", "2");
            converter.replace("CustomerName", "Mike Mueller");
            converter.replace("CustomerStreet", "Prenzlauer Berg 12");
            converter.replace("CustomerZip", "10405 Berlin");
            
            services = new ArrayList<ArrayList<String>>();
		
            subservice1 = new ArrayList<String>();
            subservice2 = new ArrayList<String>();
            subservice3 = new ArrayList<String>();
		
            subservice1.add("Software");
            subservice1.add("150");
            subservice2.add("Hardware");
            subservice2.add("500");
            subservice3.add("Test");
            subservice3.add("350");
		
            services.add(subservice1);
            services.add(subservice2);
            services.add(subservice3);
            
            converter.replace("services", services);

            converter.parse(template, invoice2);

        } catch (IOException ex) {
            System.err.println(ex.getMessage());
        }
    }
}

Finally invoice1.tex and invoice2.tex were created.
A look at invoice1.tex proves that all the tags were replaced with your data.

invoice1.tex

\documentclass{letter} 
\usepackage{invoice} 
\address{Josh Parker \\
         5650 Webster Ave \\
         West Palm Beach, Florida 33405 \\
         JParker@mail.com} 
\date{31-May-2010} 

\begin{document} 
\begin{letter}{Ivan Pfeiffer \\ 
               Schwarzer Weg 4 \\ 
               13505 Berlin} 
\opening{Invoice no. 1} 
Dear customer,

... 

\begin{invoice}{Euro}{0} 
\ProjectTitle{Example Project} 

    \Fee{Software} {50} {1} 
    \Fee{Hardware1} {500} {1} 
    \Fee{Hardware2} {850} {1} 

\end{invoice} 

\closing{Best regards} 
\end{letter} 
\end{document}     



How to use JLR to create a PDF file

The JLRGenerator uses pdfLaTeX and helps to create a PDF file from invoice1.tex and invoice2.tex.
You need to specify an output path for the PDF file and a working directory for pdfLaTeX (where realcalc.tex, invoice.sty and invoice.def lie – it’s important that pdfLaTeX is aware of such files).
In our example the working directory for pdfLaTeX is the same which we already use for the template file (C:\Invoices).

Note: If you use a portable LaTeX distribution, you need the generate()-method of JLRGenerator where you can specify the location of pdfLaTeX.

File desktop = new File(System.getProperty("user.home")	+ File.separator + "Desktop");

JLRGenerator pdfGen = new JLRGenerator();

pdfGen.generate(invoice1, desktop, workingDirectory);
File pdf1 = pdfGen.getPDF();

pdfGen.generate(invoice2, desktop, workingDirectory);
File pdf2 = pdfGen.getPDF();

Finally, you can use the JLROpener to launch the associated application and open the PDF files.

JLROpener.open(pdf1);
JLROpener.open(pdf2);




The PDF file of invoice1 should look like:



invoice1PDF.





The complete Java sample code (with error check):

Main.java

import de.nixosoft.jlr.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

public class Main {

    public static void main(String[] args) {

        File workingDirectory = new File("C:" + File.separator + "Invoices");

        File template = new File(workingDirectory.getAbsolutePath() + File.separator + "invoiceTemplate.tex");

        File tempDir = new File(workingDirectory.getAbsolutePath() + File.separator + "temp");
        if (!tempDir.isDirectory()) {
            tempDir.mkdir();
        }

        File invoice1 = new File(tempDir.getAbsolutePath() + File.separator + "invoice1.tex");
        File invoice2 = new File(tempDir.getAbsolutePath() + File.separator + "invoice2.tex");



         try {
            JLRConverter converter = new JLRConverter(workingDirectory);

            converter.replace("Number", "1");
            converter.replace("CustomerName", "Ivan Pfeiffer");
            converter.replace("CustomerStreet", "Schwarzer Weg 4");
            converter.replace("CustomerZip", "13505 Berlin");

            ArrayList<ArrayList<String>> services = new ArrayList<ArrayList<String>>();
		
            ArrayList<String> subservice1 = new ArrayList<String>();
            ArrayList<String> subservice2 = new ArrayList<String>();
            ArrayList<String> subservice3 = new ArrayList<String>();
		
            subservice1.add("Software");
            subservice1.add("50");
            subservice2.add("Hardware1");
            subservice2.add("500");
            subservice3.add("Hardware2");
            subservice3.add("850");
		
            services.add(subservice1);
            services.add(subservice2);
            services.add(subservice3);		
		
            converter.replace("services", services);
            
            if (!converter.parse(template, invoice1)) {
                System.out.println(converter.getErrorMessage());
            }



            converter.replace("Number", "2");
            converter.replace("CustomerName", "Mike Mueller");
            converter.replace("CustomerStreet", "Prenzlauer Berg 12");
            converter.replace("CustomerZip", "10405 Berlin");
            
            services = new ArrayList<ArrayList<String>>();
		
            subservice1 = new ArrayList<String>();
            subservice2 = new ArrayList<String>();
            subservice3 = new ArrayList<String>();
		
            subservice1.add("Software");
            subservice1.add("150");
            subservice2.add("Hardware");
            subservice2.add("500");
            subservice3.add("Test");
            subservice3.add("350");
		
            services.add(subservice1);
            services.add(subservice2);
            services.add(subservice3);
            
            converter.replace("services", services);

            if (!converter.parse(template, invoice2)) {
                System.out.println(converter.getErrorMessage());
            }
            

            File desktop = new File(System.getProperty("user.home") + File.separator + "Desktop");

            JLRGenerator pdfGen = new JLRGenerator();           

            if (!pdfGen.generate(invoice1, desktop, workingDirectory)) { 
                System.out.println(pdfGen.getErrorMessage());
            }

            JLROpener.open(pdfGen.getPDF());

            if (!pdfGen.generate(invoice2, desktop, workingDirectory)) {
                System.out.println(pdfGen.getErrorMessage());
            }

            JLROpener.open(pdfGen.getPDF());

        } catch (IOException ex) {
            System.err.println(ex.getMessage());
        }
    }
}

© by nixo-soft