Reputation: 302
I'm new to Apache Velocity and I would like to know what is the correct way of evaluating my context. Here is my situation:
I'd like to open a .docx
file used as template, replace some words in it with Apache Velocity
and then save the result in a new .docx
file. To do that, my code is the following:
public static void main(String[] args) {
Velocity.init();
final VelocityContext context = new VelocityContext();
context.put("city", "Firenze");
context.put("user", "Federico");
context.put("date", "23/09/20");
context.put("op", "Mario Rossi");
ArrayList<String> list = new ArrayList<String>();
list.add("Data futura");
list.add("Scrittura indecifrabile");
context.put("list", list);
String name = "tempWord.docx";
List<XWPFParagraph> paragraphs;
try {
paragraphs = readDocxFile(name);
XWPFDocument doc = new XWPFDocument();
final FileOutputStream fos = new FileOutputStream(new File("outFile.docx"));
for(XWPFParagraph para : paragraphs) {
StringWriter sw = new StringWriter();
System.out.println(para.getText());
Velocity.evaluate(context, sw, "test1", para.getText());
XWPFParagraph par = doc.createParagraph();
XWPFRun run = par.createRun();
run.setText(sw.toString());
}
doc.write(fos);
fos.close();
} catch(Exception rnfe) {
rnfe.printStackTrace();
}
}
where readDocxFile()
is a method that I've already defined and works flawlessly. What concerns me is that given this template:
${city}, ${date}
Gentile ${user},
Con la seguente la informiamo che non abbiamo potuto processare la sua richiesta a causa dei seguenti errori:
#foreach(${name} in ${list})
${name}
#end
La preghiamo dunque di correggere e sottoporre nuovamente il modulo entro e non oltre la data di scadenza.
Cordiali saluti,
${op}
I get this error
1606 [main] ERROR org.apache.velocity.parser - test1: Encountered "<EOF>" at line 1, column 29.
It happens while parsing the #foreach
loop and it seems to be related to the Velocity.evaluate()
method, since if I create a tmp.txt
file and use it as a Velocity template along with the Velocity.mergeTemplate()
method the code runs correctly. The problem with this approach is that I don't want to store a .txt
every time that I have to evaluate a context, and I must maintain the original file format.
From what I've understood evaluate()
evaluates line by line, so apparently the #foreach
block is being evaluated incorrectly.
I know that Apache POI
could also perform context replacement as well as docx4j
, but I must use Velocity.
How can I correctly evaluate the context?
Upvotes: 0
Views: 1643
Reputation: 4150
I would try to merge all paragraphs using a custom separator, and then split the result upon that separator to rebuild the paragraphs. Something along the lines of:
try {
paragraphs = readDocxFile(name);
XWPFDocument doc = new XWPFDocument();
final FileOutputStream fos = new FileOutputStream(new File("outFile.docx"));
StringWriter sw = new StringWriter();
String separator = "_PARA_";
for(XWPFParagraph para : paragraphs) {
System.out.println(para.getText());
sw.append(para.getText());
sw.append(separator);
}
StringWriter rst = new StringWriter();
Velocity.evaluate(context, rst, "test1", sw.toString);
for (String para : rst.toString().split(separator))
XWPFParagraph par = doc.createParagraph();
XWPFRun run = par.createRun();
run.setText(para);
}
doc.write(fos);
fos.close();
} catch(Exception rnfe) {
rnfe.printStackTrace();
}
You're probably aware, though, that by converting back and forth paragraphs to text like this, you are susceptible to loose formatting tags, not to speak about titles,tables, enumerations, etc. It should properly work for standard body text, though.
Upvotes: 0