Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package ro.dabuno.office.integration; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlOptions; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody; /** * Simple application which performs a "mail-merge" of a Microsoft Word template * document which contains replacement templates in the form of ${name}, ${first-name}, ... * and an Microsoft Excel spreadsheet which contains a list of entries that are merged in. * * Call this application with parameters <word-template> <excel/csv-template> <output-file> * * The resulting document has all resulting documents concatenated. * * @author dominik.stadler * */ public class MailMerge { private static final Logger log = LogManager.getLogger(MailMerge.class); public static void main(String[] args) throws Exception { if (args.length != 3) { throw new IllegalArgumentException( "Usage: MailMerge <word-template> <excel/csv-template> <output-file>"); } File wordTemplate = new File(args[0]); File excelFile = new File(args[1]); String outputFile = args[2]; if (!wordTemplate.exists() || !wordTemplate.isFile()) { throw new IllegalArgumentException("Could not read Microsoft Word template " + wordTemplate); } if (!excelFile.exists() || !excelFile.isFile()) { throw new IllegalArgumentException("Could not read data file " + excelFile); } new MailMerge().merge(wordTemplate, excelFile, outputFile); } private void merge(File wordTemplate, File dataFile, String outputFile) throws Exception { log.info("Merging data from " + wordTemplate + " and " + dataFile + " into " + outputFile); // read the data-rows from the CSV or XLS(X) file Data data = new Data(); data.read(dataFile); // now open the word file and apply the changes try (InputStream is = new FileInputStream(wordTemplate)) { try (XWPFDocument doc = new XWPFDocument(is)) { // apply the lines and concatenate the results into the document applyLines(data, doc); log.info("Writing overall result to " + outputFile); try (OutputStream out = new FileOutputStream(outputFile)) { doc.write(out); } } } } private void applyLines(Data dataIn, XWPFDocument doc) throws XmlException, IOException { CTBody body = doc.getDocument().getBody(); XmlOptions optionsOuter = new XmlOptions(); optionsOuter.setSaveOuter(); // read the current full Body text String srcString = body.xmlText(); // apply the replacements boolean first = true; List<String> headers = dataIn.getHeaders(); for (List<String> data : dataIn.getData()) { log.info("Applying to template: " + data); String replaced = srcString; for (int fieldNr = 0; fieldNr < headers.size(); fieldNr++) { String header = headers.get(fieldNr); String value = data.get(fieldNr); // ignore columns without headers as we cannot match them if (header == null) { continue; } // use empty string for data-cells that have no value if (value == null) { value = ""; } replaced = replaced.replace("${" + header + "}", value); } // check for missed replacements or formatting which interferes if (replaced.contains("${")) { log.warn("Still found template-marker after doing replacement: " + StringUtils.abbreviate(StringUtils.substring(replaced, replaced.indexOf("${")), 200)); } appendBody(body, replaced, first); first = false; } } private static void appendBody(CTBody src, String append, boolean first) throws XmlException { XmlOptions optionsOuter = new XmlOptions(); optionsOuter.setSaveOuter(); String srcString = src.xmlText(); String prefix = srcString.substring(0, srcString.indexOf(">") + 1); final String mainPart; // exclude template itself in first appending if (first) { mainPart = ""; } else { mainPart = srcString.substring(srcString.indexOf(">") + 1, srcString.lastIndexOf("<")); } String sufix = srcString.substring(srcString.lastIndexOf("<")); String addPart = append.substring(append.indexOf(">") + 1, append.lastIndexOf("<")); CTBody makeBody = CTBody.Factory.parse(prefix + mainPart + addPart + sufix); src.set(makeBody); } }