Hack: ODF + StringTemplate

Dezembro 27, 2007

Precisei fazer um gerador de relatório para um pequeno projeto, o problema que era algo muito bem formatado, com tabelas e fontes de diversos tipos, no início pensei em usar HTML + StringTemplate mas padrões abertos funcionam na prática.

Os arquivos ODF são pastas zipadas com conteúdos como imagens e arquivos xml que definem o documento. Mais especificamente o arquivo content.xml que define a formatação junto com o texto. Mas não foi nem nescessário saber as tags para o hack (Ok, gambiarra).

StringTemplate

StringTemplate é uma biblioteca para java. A funcionalidade dela é substituir em Strings os trechos demarcados previamente com outras Strings. Com um exemplo é mais fácil.


String message = "Ola $NAME$ e tchau $MESSAGE$.";

StringTemplate template = new StringTemplate(message);
template.setAttribute("NAME", "Renan careilhos");
template.setAttribute("MESSAGE", "e va para o inferno");

System.out.println(template.toString());

Imprime: Ola Renan calheiros e tchau e va para o inferno.Os trechos demarcados previamente, na terminologia da StringTemplate, são as palavras circuladas por ‘$’ e se chamam attributes.

ODF4J

ODF4J é uma biblioteca para java criada para ler pacotes ODF. Ela é mantida pelo projeto OpenOffice.

A Gambiarra

Como o texto e formatação de um arquivo ODT é um text/xml, então não precisamos nos dar o trabalho nem de sair do Writer, podemos colocar os atributos da StringTemplate ali mesmo. Tipo esse documento

Em baixo um trecho do projeto.


import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import org.antlr.stringtemplate.StringTemplate;
import org.openoffice.odf.OdfPackage;
import org.openoffice.odf.OpenDocumentFactory;

public class OdtExamReportGenerator implements ExamReportGenerator {
    private StringTemplate odtTemplate;
    private OdfPackage odfPack;

    public OdtExamReportGenerator(File template) throws IOException {
//Abre o documento ODT
        odfPack = OpenDocumentFactory.load(template);

// Lê a o arquivo principal, content.xml, para um buffer auxiliar
        StringBuffer buffer = new StringBuffer();
        BufferedReader reader = new BufferedReader(new InputStreamReader(odfPack.getXMLInputStream("content.xml")));

        String line;
        while ( (line = reader.readLine()) != null ) {
            buffer.append(line);
        }

// Cria o template
        odtTemplate = new StringTemplate(buffer.toString());
    }

    public void generateReport(Exam exam, String filename) throws GeneratorException {
        try {
            odtTemplate.setAttribute("NOME", exam.getName());
            odtTemplate.setAttribute("TIPO", exam.getType());
            odtTemplate.setAttribute("NUMERO", exam.getNumber());

// O método store insere ou substitui no pacote ODF um arquivo, seguidos dos bytes e do tipo MIME text/xml
            odfPack.store("content.xml", odtTemplate.toString().getBytes(),"text/xml");

// Salva o pacote ODF.
            odfPack.save(filename);
        } catch (FileNotFoundException ex) {
            throw new GeneratorException(ex.getMessage(), ex);
        } catch (IOException ex) {
            throw new GeneratorException(ex.getMessage(), ex);
        }
    }
}

E por último…

Não testei com templates muito grandes, e além do mais, ODF gera bastante XML. Mas duvido que java não tenha peformance para analisar templates de relatórios do INPS.

Deixe um comentário