DocxProcess.DocxTemplateReplacer.java Source code

Java tutorial

Introduction

Here is the source code for DocxProcess.DocxTemplateReplacer.java

Source

/*
 * 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;
    }
}