All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.joylau.office.word.support.template.expression.GroovyExpressionRunner Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (c) 2017 by JoyLau. All rights reserved
 ******************************************************************************/

package cn.joylau.office.word.support.template.expression;

import cn.joylau.commons.utils.ListUtils;
import cn.joylau.commons.utils.StringUtils;
import cn.joylau.office.word.support.template.expression.helper.ParagraphHelper;
import cn.joylau.office.word.support.template.expression.helper.TableHelper;
import cn.joylau.scripts.engine.DynamicScriptEngine;
import cn.joylau.scripts.engine.DynamicScriptEngineFactory;
import cn.joylau.scripts.engine.ExecuteResult;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText;

import java.util.*;

/**
 * 基于Groovy的表达式运行器
 * 原理:通过解析word中的表达式,拼接为groovy脚本,然后执行
 * 当前版本已支持:
 * 段落:
 * 
    *
  • 变量引用: ${name}
  • *
* 表格: *
    *
  • 变量引用: ${name}
  • *
  • 循环: ${for(data in list)} | ${data.name} |${data.addr} |${/for} 。注意:表达式必须在一行
  • *
*/ public class GroovyExpressionRunner implements ExpressionRunner { /** * 内置变量标识 */ private int flag = 0; /** * 循环标识 */ private int eachFlag = 0; /** * 表格循环标识 */ private int t_eachFlag = 0; /** * if标识 */ private int ifFlag = 0; /** * 脚本 */ private StringBuilder script = new StringBuilder(); /** * 变量 */ private Map vars = new HashMap<>(); /** * 段落辅助器 */ private WordHelper helper = new ParagraphHelper(); /** * 表格辅助器 */ private WordHelper cellHelper = new TableHelper(); protected int nextFlag() { return ++flag; } @Override public void pushExpression(String expression, Object paragraph) { XWPFParagraph xwpfParagraph = ((XWPFParagraph) paragraph); List infoList = parseExpression(xwpfParagraph); if (infoList.size() == 0) return; String p_id = "paragraph_" + nextFlag(); String info_id = "infoList_" + nextFlag(); vars.put(info_id, infoList); vars.put(p_id, paragraph); for (ExpressInfo expressInfo : infoList) { String s = expressInfo.getExpress(); s = s.substring(2); s = s.substring(0, s.length() - 1).trim(); if (s.startsWith("if")) { ifFlag++; script.append(s).append("{\n"); expressInfo.setKeyWord(true); } else if (s.startsWith("/if")) { ifFlag--; script.append("}\n"); expressInfo.setKeyWord(true); } else { String exp_id = "expression_" + nextFlag(); vars.put(exp_id, expressInfo); script.append(StringUtils.concat(exp_id, ".setValue(", s, ");\n")); } } script.append(StringUtils.concat("_helper.init(", info_id, ",", p_id, ");\n")); } /** * 表达式解析 * * @param paragraph 段落 * @return 表达式信息集合 */ protected List parseExpression(XWPFParagraph paragraph) { List expressInfos = new LinkedList<>(); List runs = paragraph.getRuns(); boolean inExpress = false; ExpressInfo temp = null; int index = 0; for (int i = 0; i < runs.size(); i++) { XWPFRun run = runs.get(i); CTR ctr = run.getCTR(); for (CTText ctText : ctr.getTList()) { String text = ctText.getStringValue(); boolean now = false; if (text.contains("$")) { inExpress = true; temp = new ExpressInfo(); temp.setStartWith(index); temp.setRun(run); String[] t = text.split("\\$"); if (t.length > 1) { temp.push("$" + t[1]); } else { temp.push("$"); } now = true; } if ((inExpress) && text.contains("}")) { temp.setEndWith(index); if (now) { temp.push("}"); } else { String[] t = text.split("\\}"); if (t.length > 0) temp.push(t[0] + "}"); else temp.push("}"); } expressInfos.add(temp); now = true; temp = null; inExpress = false; } if (inExpress && !now) { temp.push(text); } index++; } } return expressInfos; } /** * 段落内容解析为表达式集合,此方法并不是很好,主要用于表格渲染使用 * 下一步将进行优化 * * @param expression 表达式内容 * @return */ protected List parseExpression(String expression) { String tmp[] = expression.split("\\$\\{"); List strList = new ArrayList<>(); for (String s : tmp) { s = s.replace("{", "{").replace("}", "}"); if (!s.contains("}")) { if (!StringUtils.isNullOrEmpty(s)) strList.add(StringUtils.concat("\"", s.replace("\"", "\\\""), "\"")); } else { String temp2[] = s.split("\\}"); if (temp2.length == 0) continue; strList.add(temp2[0].trim().replace("”", "\"").replace("“", "\"").replace("‘", "'").replace("’", "'")); if (temp2.length > 1) { strList.add(StringUtils.concat("\"", temp2[1].replace("\"", "\\\""), "\"")); } } } return strList; } /** * 表格,此方法仅能渲染简单的表格,不能复制样式等信息,有待优化 * * @param expression 表达式内容 * @param cell 单元格实例 * @param paragraph 单元格段落实例 */ @Override public void pushExpression(String expression, Object cell, Object paragraph) { XWPFTableCell cell1 = ((XWPFTableCell) cell); XWPFParagraph xwpfParagraph = ((XWPFParagraph) paragraph); String p_id = "paragraph_" + nextFlag(); String c_id = "cell_" + nextFlag(); List expressionList = parseExpression(expression); vars.put(p_id, paragraph); vars.put(c_id, cell); List temp = new ArrayList<>(); boolean endEach = false; for (String s : expressionList) { if (s.startsWith("for")) { t_eachFlag++; script.append(s).append("{\n"); script.append(StringUtils.concat("_cellHelper.nextRow(", c_id, ");\n")); } else if (s.startsWith("/for")) { t_eachFlag--; script.append(StringUtils.concat("_cellHelper.nextCell(", c_id, ",", ListUtils.toString(temp.toArray()), ");\n")); endEach = true; script.append("}\n"); } else { temp.add(s); } } if (t_eachFlag > 0) { script.append(StringUtils.concat("_cellHelper.nextCell(", c_id, ",", ListUtils.toString(temp.toArray()), ");\n")); } else { if (!endEach) script.append(StringUtils.concat("_helper.initParaGraph(", p_id, ",", ListUtils.toString(temp.toArray()), ");\n")); } } @Override public void setVar(Map var) { vars.putAll(var); } @Override public void run() throws Throwable { vars.put("_helper", helper); vars.put("_cellHelper", cellHelper); DynamicScriptEngine engine = DynamicScriptEngineFactory.getEngine("groovy"); String id = "word.runner." + script.hashCode(); if (!engine.compiled(id)) { engine.compile(id, script.toString()); } ExecuteResult result = engine.execute(id, vars); if (result.getException() != null) { throw result.getException(); } } /** * 表达式信息 */ public static class ExpressInfo { //内容 private String express = ""; private XWPFRun run; //表达式在段落中的开始下标 private int startWith; //表达式在段落中的结束下标 private int endWith; //表达式的真实值 private Object value; //是否为关键字表达式,如:for,if等等,如果为true,辅助器应当不进行渲染 private boolean keyWord; public boolean isKeyWord() { return keyWord; } public void setKeyWord(boolean keyWord) { this.keyWord = keyWord; } public void push(String str) { str = str.replace("”", "\"").replace("“", "\"").replace("‘", "'").replace("’", "'"); if (str.equals("}") && express.endsWith("}")) return; express = express + str; } public Object getValue() { return value; } public void setValue(Object value) { this.value = value; } public XWPFRun getRun() { return run; } public void setRun(XWPFRun run) { this.run = run; } public String getExpress() { return express; } public void setExpress(String express) { this.express = express; } public int getStartWith() { return startWith; } public void setStartWith(int startWith) { this.startWith = startWith; } public int getEndWith() { return endWith; } public void setEndWith(int endWith) { this.endWith = endWith; } @Override public String toString() { return "ExpressInfo{" + "express='" + express + '\'' + ", run=" + run + ", startWith=" + startWith + ", endWith=" + endWith + ", value=" + value + '}'; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy