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 DocxProcess; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.apache.poi.xwpf.usermodel.XWPFTableCell; import org.apache.poi.xwpf.usermodel.XWPFTableRow; /** * * @author hanson */ public class DocxTemplateReplacer { public XWPFDocument docx; public static void main(String args[]) throws FileNotFoundException { String directory = System.getProperty("user.dir") + "/"; String fileName = "/Template-Number.docx"; String path = directory + fileName; Map<String, String> pattern = new HashMap(); pattern.put("n1", "99"); pattern.put("n2", "7"); DocxTemplateReplacer replacer = new DocxTemplateReplacer(new FileInputStream(path)); replacer.replace(pattern); ReadWordDocx reader = new ReadWordDocx(); replacer.writeOutDocx(System.getProperty("user.dir") + "/output"); } public DocxTemplateReplacer(InputStream is) { try { this.docx = new XWPFDocument(is); } catch (IOException e) { System.err.println("File isn't docx."); } } public void writeOutDocx(String path) { try { this.docx.write(new FileOutputStream(path)); docx.close(); } catch (IOException e) { System.err.println(path + " write-out failed."); } } public void replace(Map<String, String> data) { for (XWPFParagraph p : docx.getParagraphs()) { replaceParagraph(p, data); } for (XWPFTable tbl : docx.getTables()) { for (XWPFTableRow row : tbl.getRows()) { for (XWPFTableCell cell : row.getTableCells()) { for (XWPFParagraph p : cell.getParagraphs()) { replaceParagraph(p, data); } } } } } public XWPFDocument get() { return this.docx; } private void replaceParagraph(XWPFParagraph p, Map<String, String> data) { String pText = p.getText(); // complete paragraph as string if (pText.contains("${")) { // if paragraph does not include our pattern, ignore TreeMap<Integer, XWPFRun> posRuns = getPosToRuns(p); Pattern pat = Pattern.compile("\\$\\{(.+?)\\}"); Matcher m = pat.matcher(pText); while (m.find()) { // for all patterns in the paragraph String g = m.group(1); // extract key start and end pos int s = m.start(1); int e = m.end(1); String key = g; String x = data.get(key); if (x == null) x = ""; SortedMap<Integer, XWPFRun> range = posRuns.subMap(s - 2, true, e + 1, true); // get runs which contain the pattern boolean found1 = false; // found $ boolean found2 = false; // found { boolean found3 = false; // found } XWPFRun prevRun = null; // previous run handled in the loop XWPFRun found2Run = null; // run in which { was found int found2Pos = -1; // pos of { within above run for (XWPFRun r : range.values()) { if (r == prevRun) continue; // this run has already been handled if (found3) break; // done working on current key pattern prevRun = r; for (int k = 0;; k++) { // iterate over texts of run r if (found3) break; String txt = null; try { txt = r.getText(k); // note: should return null, but throws exception if the text does not exist } catch (Exception ex) { } if (txt == null) break; // no more texts in the run, exit loop if (txt.contains("$") && !found1) { // found $, replaceAll it with value from data map txt = txt.replaceFirst("\\$", x); found1 = true; } if (txt.contains("{") && !found2 && found1) { found2Run = r; // found { replaceAll it with empty string and remember location found2Pos = txt.indexOf('{'); txt = txt.replaceFirst("\\{", ""); found2 = true; } if (found1 && found2 && !found3) { // find } and set all chars between { and } to blank if (txt.contains("}")) { if (r == found2Run) { // complete pattern was within a single run txt = txt.substring(0, found2Pos) + txt.substring(txt.indexOf('}')); } else // pattern spread across multiple runs txt = txt.substring(txt.indexOf('}')); } else if (r == found2Run) // same run as { but no }, remove all text starting at { txt = txt.substring(0, found2Pos); else txt = ""; // run between { and }, set text to blank } if (txt.contains("}") && !found3) { txt = txt.replaceFirst("\\}", ""); found3 = true; } r.setText(txt, k); } } } // System.out.println(p.getText()); } } private TreeMap<Integer, XWPFRun> getPosToRuns(XWPFParagraph paragraph) { int pos = 0; TreeMap<Integer, XWPFRun> map = new TreeMap<Integer, XWPFRun>(); for (XWPFRun run : paragraph.getRuns()) { String runText = run.text(); if (runText != null && runText.length() > 0) { for (int i = 0; i < runText.length(); i++) { map.put(pos + i, run); } pos += runText.length(); } } return map; } }