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.