步骤一:把模板后缀名修改为zip解压
步骤二:打开word/document.xml
步骤三:把所有${不连续的修改为连续,如${1,}修改为${1}
步骤五:选中解压内容压缩为zip,修改后缀名为docx
下面举个实际例子:
如果数据是静态的
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File(inputfilepath)); MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart(); HashMap<String, String> staticMap = getStaticData(); // 替换普通变量 documentPart.variableReplace(staticMap); // 保存结果 saveWordPackage(wordMLPackage, outputfilepath);
替换完成,后面的东西没必要看了。
如果内容中有普通表格且表格内容有动态数据,如
层次、民族数据是动态的,保证表格有数据,即打开word/document.xml看到如下内容tc下面只有一个t:
参考例子如下:
import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import javax.xml.bind.JAXBElement; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomUtils; import org.docx4j.TraversalUtil; import org.docx4j.XmlUtils; import org.docx4j.dml.chart.CTChartSpace; import org.docx4j.dml.chart.CTNumDataSource; import org.docx4j.dml.chart.CTNumVal; import org.docx4j.dml.chart.CTPieChart; import org.docx4j.dml.chart.CTPieSer; import org.docx4j.jaxb.Context; import org.docx4j.openpackaging.exceptions.Docx4JException; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.openpackaging.parts.DrawingML.Chart; import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; import org.docx4j.openpackaging.parts.relationships.Namespaces; import org.docx4j.openpackaging.parts.relationships.RelationshipsPart; import org.docx4j.relationships.Relationship; import org.docx4j.wml.Body; import org.docx4j.wml.Br; import org.docx4j.wml.ContentAccessor; import org.docx4j.wml.Document; import org.docx4j.wml.P; import org.docx4j.wml.R; import org.docx4j.wml.Tbl; import org.docx4j.wml.Tc; import org.docx4j.wml.TcPr; import org.docx4j.wml.TcPrInner.VMerge; import org.docx4j.wml.Text; import org.docx4j.wml.Tr; import org.docx4j.wml.TrPr; import org.junit.Test; public class Docx4j_替换模板 { private String inputfilepath = "E:/test_tmp/0904/test_docx.docx"; private static final String outputfilepath = "e:/test_tmp/0904/sys_" + System.currentTimeMillis() + ".docx"; public static org.docx4j.wml.ObjectFactory factory = Context.getWmlObjectFactory(); @Test public void testReplaceTemplateDocx() throws Exception { replaceTemplateDocx(); } public void replaceTemplateDocx() throws Exception { WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File(inputfilepath)); MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart(); HashMap<String, String> staticMap = getStaticData(); // 替换普通变量 documentPart.variableReplace(staticMap); Document document = (Document) documentPart.getContents(); Body body = document.getBody(); MyTblFinder tblFinder = new MyTblFinder(); new TraversalUtil(body, tblFinder); // 替换表格模板第三行数据 Tbl firstTbl = tblFinder.getTbls().get(0); List<Object> trObjList = firstTbl.getContent(); Tr tr = (Tr) trObjList.get(2); replaceTrTotalData(tr, getTotalData()); int lvlIndex = 3; // 替换表格模板第四行数据 int lvlTotalSize = 4; tr = (Tr) trObjList.get(lvlIndex); List<String[]> lvDataList = getLvDataList(lvlTotalSize); replaceTrData(firstTbl, tr, lvDataList, lvlIndex); // 重新获取表格数据 trObjList = firstTbl.getContent(); int sexTotalSize = 2; // 替换表格模板第五行数据 tr = (Tr) trObjList.get(lvlIndex + lvlTotalSize); List<String[]> sexDataList = getSexDataList(2); replaceTrSexData(tr, sexDataList.get(0)); // 替换表格模板第六行数据 tr = (Tr) trObjList.get(4 + lvlTotalSize); replaceTrSexData(tr, sexDataList.get(1)); // 替换表格模板第七行数据 tr = (Tr) trObjList.get(5 + lvlTotalSize); int nationTotalSize = 56; List<String[]> nationDataList = getNationDataList(nationTotalSize); replaceTrData(firstTbl, tr, nationDataList, lvlIndex+lvlTotalSize+sexTotalSize); // 合并层次单元格 层次位于第3行 mergeCellsVertically(firstTbl, 0, lvlIndex, lvlIndex + lvlTotalSize - 1); // 合并民族单元格 层次+性别2行 mergeCellsVertically(firstTbl, 0, lvlIndex + lvlTotalSize + sexTotalSize, lvlIndex + lvlTotalSize + sexTotalSize + nationTotalSize - 1); // 替换图表数据 String[] chartArr = getChartData(); replacePieChartData(wordMLPackage, chartArr); // 保存结果 saveWordPackage(wordMLPackage, outputfilepath); } /** * 替换图表数据 */ private void replacePieChartData(WordprocessingMLPackage wordMLPackage, String[] chartArr) throws Docx4JException { RelationshipsPart rp = wordMLPackage.getMainDocumentPart().getRelationshipsPart(); Relationship rel = rp.getRelationshipByType(Namespaces.SPREADSHEETML_CHART); Chart chart = (Chart) rp.getPart(rel); CTChartSpace chartSpace = chart.getContents(); List<Object> charObjList = chartSpace.getChart().getPlotArea().getAreaChartOrArea3DChartOrLineChart(); CTPieChart pieChart = (CTPieChart) charObjList.get(0); List<CTPieSer> serList = pieChart.getSer(); CTNumDataSource serVal = serList.get(0).getVal(); List<CTNumVal> ptList = serVal.getNumRef().getNumCache().getPt(); ptList.get(0).setV(chartArr[0]); ptList.get(1).setV(chartArr[1]); } /** * 替换tr数据 */ private void replaceTrSexData(Tr tr, String[] dataArr) throws Exception { List<Tc> tcList = getTrAllCell(tr); Tc tc = null; for (int i = 2, iLen = tcList.size(); i < iLen; i++) { tc = tcList.get(i); replaceTcContent(tc, dataArr[i - 2]); } } /** * 替换tr数据,其他插入 */ private void replaceTrData(Tbl tbl, Tr tr, List<String[]> dataList, int trIndex) throws Exception { TrPr trPr = XmlUtils.deepCopy(tr.getTrPr()); String tcContent = null; String[] tcMarshaArr = getTcMarshalStr(tr); String[] dataArr = null; for (int i = 0, iLen = dataList.size(); i < iLen; i++) { dataArr = dataList.get(i); Tr newTr = null; Tc newTc = null; if (i == 0) { newTr = tr; } else { newTr = factory.createTr(); if (trPr != null) { newTr.setTrPr(trPr); } newTc = factory.createTc(); newTr.getContent().add(newTc); } for (int j = 0, jLen = dataArr.length; j < jLen; j++) { tcContent = tcMarshaArr[j]; if (tcContent != null) { tcContent = tcContent.replaceAll("(<w:t>)(.*?)(</w:t>)", "<w:t>" + dataArr[j] + "</w:t>"); newTc = (Tc) XmlUtils.unmarshalString(tcContent); } else { newTc = factory.createTc(); setNewTcContent(newTc, dataArr[j]); } // 新增tr if (i != 0) { newTr.getContent().add(newTc); } else { // 替换 newTr.getContent().set(j + 1, newTc); } } if(i!=0){ tbl.getContent().add(trIndex+i, newTr); } } } /** * 获取单元格字符串 */ private String[] getTcMarshalStr(Tr tr) { List<Object> tcObjList = tr.getContent(); String[] marshaArr = new String[7]; // 跳过层次 for (int i = 1, len = tcObjList.size(); i < len; i++) { marshaArr[i - 1] = XmlUtils.marshaltoString(tcObjList.get(i), true, false); } return marshaArr; } /** * 替换表格合计数据 */ private void replaceTrTotalData(Tr tr, String[] dataArr) { List<Object> tcObjList = tr.getContent(); Tc tc = null; // 跳过合计 for (int i = 2, len = tcObjList.size(); i < len; i++) { tc = (Tc) XmlUtils.unwrap(tcObjList.get(i)); replaceTcContent(tc, dataArr[i - 2]); } } /** * 替换单元格内容 */ private void replaceTcContent(Tc tc, String value) { List<Object> rtnList = getAllElementFromObject(tc, Text.class); if (rtnList == null || rtnList.size() == 0) { return; } Text textElement = (Text) rtnList.get(0); textElement.setValue(value); } /** * 设置单元格内容 * * @param tc * @param content */ public static void setNewTcContent(Tc tc, String content) { P p = factory.createP(); tc.getContent().add(p); R run = factory.createR(); p.getContent().add(run); if (content != null) { String[] contentArr = content.split("\n"); Text text = factory.createText(); text.setSpace("preserve"); text.setValue(contentArr[0]); run.getContent().add(text); for (int i = 1, len = contentArr.length; i < len; i++) { Br br = factory.createBr(); run.getContent().add(br);// 换行 text = factory.createText(); text.setSpace("preserve"); text.setValue(contentArr[i]); run.getContent().add(text); } } } /** * @Description: 跨行合并 */ public static void mergeCellsVertically(Tbl tbl, int col, int fromRow, int toRow) { if (col < 0 || fromRow < 0 || toRow < 0) { return; } for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) { Tc tc = getTc(tbl, rowIndex, col); if (tc == null) { break; } TcPr tcPr = getTcPr(tc); VMerge vMerge = tcPr.getVMerge(); if (vMerge == null) { vMerge = factory.createTcPrInnerVMerge(); tcPr.setVMerge(vMerge); } if (rowIndex == fromRow) { vMerge.setVal("restart"); } else { vMerge.setVal("continue"); } } } public static TcPr getTcPr(Tc tc) { TcPr tcPr = tc.getTcPr(); if (tcPr == null) { tcPr = new TcPr(); tc.setTcPr(tcPr); } return tcPr; } public static Tc getTc(Tbl tbl, int row, int cell) { if (row < 0 || cell < 0) { return null; } List<Tr> trList = getTblAllTr(tbl); if (row >= trList.size()) { return null; } List<Tc> tcList = getTrAllCell(trList.get(row)); if (cell >= tcList.size()) { return null; } return tcList.get(cell); } public static List<Tc> getTrAllCell(Tr tr) { List<Object> objList = getAllElementFromObject(tr, Tc.class); List<Tc> tcList = new ArrayList<Tc>(); if (objList == null) { return tcList; } for (Object tcObj : objList) { if (tcObj instanceof Tc) { Tc objTc = (Tc) tcObj; tcList.add(objTc); } } return tcList; } public static List<Tr> getTblAllTr(Tbl tbl) { List<Object> objList = getAllElementFromObject(tbl, Tr.class); List<Tr> trList = new ArrayList<Tr>(); if (objList == null) { return trList; } for (Object obj : objList) { if (obj instanceof Tr) { Tr tr = (Tr) obj; trList.add(tr); } } return trList; } /** * 按class获取内容 */ public static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) { List<Object> result = new ArrayList<Object>(); if (obj instanceof JAXBElement) { obj = ((JAXBElement<?>) obj).getValue(); } if (obj.getClass().equals(toSearch)) { result.add(obj); } else if (obj instanceof ContentAccessor) { List<?> children = ((ContentAccessor) obj).getContent(); for (Object child : children) { result.addAll(getAllElementFromObject(child, toSearch)); } } return result; } /** * 保存文档 */ public static void saveWordPackage(WordprocessingMLPackage wordPackage, String filePath) throws Exception { wordPackage.save(new File(filePath)); } /** * 获取图表数据 */ private String[] getChartData() { int[] intArr = new int[] { RandomUtils.nextInt(1, 99), 0 }; intArr[1] = 100 - intArr[0]; return new String[] { Integer.toString(intArr[0]), Integer.toString(intArr[1]) }; } /** * 获取民族数据 */ private List<String[]> getNationDataList(int total) { List<String[]> dataList = new ArrayList<String[]>(); for (int i = 0; i < total; i++) { dataList.add( new String[] { "民族_" + i, RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2) }); } return dataList; } /** * 获取性别数据 */ private List<String[]> getSexDataList(int total) { List<String[]> dataList = new ArrayList<String[]>(); // 男 dataList.add(new String[] { RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2) }); // 女 dataList.add(new String[] { RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2) }); return dataList; } /** * 获取层次数据 */ private List<String[]> getLvDataList(int total) { List<String[]> dataList = new ArrayList<String[]>(); for (int i = 0; i < total; i++) { dataList.add( new String[] { "本科_" + i, RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2), RandomStringUtils.randomNumeric(2) }); } return dataList; } /** * 获取合计数据 */ private String[] getTotalData() { return new String[] { "2000", "44.4", "2500", "55.5", "500", "11.11" }; } /** * 获取静态数据 */ private HashMap<String, String> getStaticData() { HashMap<String, String> dataMap = new HashMap<String, String>(); dataMap.put("Pg1-1", "2016"); dataMap.put("Pg1-2", "11"); dataMap.put("Pg1-02", "18"); dataMap.put("Pg1-3", "2000"); dataMap.put("Pg1-4", "500"); dataMap.put("Pg1-5", "1500"); dataMap.put("Pg1-6", "900"); dataMap.put("Pg1-7", "600"); dataMap.put("Pg1-8", "2015"); dataMap.put("Pg1-9", "1000"); dataMap.put("Pg1-10", "10"); dataMap.put("Pg1-11", "1"); dataMap.put("Pg1-12", "5"); dataMap.put("Pg1-13", "3"); dataMap.put("Pg1-14", "4"); dataMap.put("Tb1-24", "25"); dataMap.put("Tb1-44", "45"); dataMap.put("Tb1-54", "30"); dataMap.put("Pg2-1", "1200"); dataMap.put("Tb1-64", "60"); dataMap.put("Pg2-2", "800"); dataMap.put("Tb1-74", "40"); dataMap.put("Pg2-3", "0.66"); return dataMap; } }
import java.util.ArrayList; import java.util.List; import org.docx4j.TraversalUtil.CallbackImpl; import org.docx4j.wml.Tbl; public class MyTblFinder extends CallbackImpl { public List<Tbl> tblList = new ArrayList<Tbl>(); public List<Object> apply(Object o) { if (o instanceof Tbl) { tblList.add((Tbl) o); } return null; } public boolean shouldTraverse(Object o) { return !(o instanceof Tbl); } public List<Tbl> getTbls() { return tblList; } }
结果为:
全文完。