2 * Copyright 2014 Hanei Management Co.,Ltd.
4 * This file is part of Jaxcel
6 * Jaxcel is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Jaxcel is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 package org.hanei.jaxcel.report;
21 import java.text.ParseException;
22 import java.util.ArrayList;
23 import java.util.Date;
24 import java.util.Locale;
26 import java.util.TimeZone;
27 import java.util.regex.Matcher;
28 import java.util.regex.Pattern;
31 import org.apache.commons.lang3.BooleanUtils;
32 import org.apache.commons.lang3.StringUtils;
33 import org.apache.commons.lang3.math.NumberUtils;
34 import org.apache.commons.lang3.time.DateUtils;
35 import org.apache.poi.POIXMLDocumentPart;
36 import org.apache.poi.hssf.record.cf.CellRangeUtil;
37 import org.apache.poi.ss.formula.FormulaParseException;
38 import org.apache.poi.ss.usermodel.Cell;
39 import org.apache.poi.ss.usermodel.Row;
40 import org.apache.poi.ss.usermodel.Sheet;
41 import org.apache.poi.ss.util.CellRangeAddress;
42 import org.apache.poi.ss.util.CellReference;
43 import org.apache.poi.xssf.usermodel.XSSFDrawing;
44 import org.apache.poi.xssf.usermodel.XSSFSheet;
45 import org.hanei.jaxcel.exception.JaxcelInputException;
46 import org.hanei.jaxcel.util.ExcelUtil;
47 import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing;
48 import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
49 import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor;
50 import org.slf4j.LoggerFactory;
51 import org.slf4j.Logger;
54 * Excelテンプレートシートの指示子(Template Language)、EL式(Expression Language)の検索、パースを行う
56 * @author Noboru Saito
59 public class TLParser {
61 private static final Logger log = LoggerFactory.getLogger(TLParser.class);
63 private static final String EL = "el";
64 private static final String TL_IF = "if";
65 private static final String TL_FOREACH = "foreach";
66 private static final String TLP_EXPR = "${";
67 private static final String TLP_DELETE = "delete";
68 private static final String TLP_DIRECTION = "direction";
69 private static final String TLP_SHIFT = "shift";
70 private static final String TLP_BLOCK = "block";
71 private static final String TLP_STYLE = "style";
72 private static final String TLP_START = "start";
73 private static final String TLP_END = "end";
74 private static final String TLP_ROWS = "rows";
75 private static final String TLP_COLS = "cols";
77 private static final String LEFT = "left";
78 private static final String UP = "up";
79 private static final String CLEAR = "clear";
80 private static final String ROW = "row";
81 private static final String COL = "col";
82 private static final String COPY = "copy";
83 private static final int SPAN_DEF = 1;
84 private static final int IDX_BASE = 1;
85 private static final int PARSE_MAX = 10;
87 private static final short FORMAT_GENERAL = 0;
88 private static final short FORMAT_TEXT = 49;
90 private Sheet sheet = null;
91 private JaxcelContext context = null;
92 private ELManager elMgr = null;
93 private Cell cell = null;
94 private int startRowIdx;
95 private int startColIdx;
97 private String type; // TL式のタイプ
98 private String expression; // EL式
99 private String delete; // delete
100 private int rowSpan; // row
101 private int colSpan; // column
102 private String direction; // direction
103 private boolean shift; // shift
104 private boolean block; // block
105 private String style; // style
106 private String start; // start
107 private String end; // end
108 private String list; // list
109 private String object; // object
110 private String matchString; // マッチした文字列保持用
111 private boolean reParseFlg; // 同一セル再パース要否フラグ
112 private int parseCount; // 同一セルパース回数
117 private final String rgEl = "\\$\\{([^\\{\\}]+)\\}";
118 private final Pattern ptEl = Pattern.compile(rgEl);
119 private Matcher mtEl;
122 * #if(${expression} delete:"up|left|clear" block:"true|false" rows:"number" cols:"number")
124 private final String rgIf = "#if\\(\\s*(\\$\\{[^\\{\\}]+\\})(?:\\s+(?:(delete\\s*:\\s*\"[^\"]*\")|(block\\s*:\\s*\"[^\"]*\")|(rows\\s*:\\s*\"\\d+\")|(cols\\s*:\\s*\"\\d+\"))){0,4}\\s*\\)";
125 private final Pattern ptIf = Pattern.compile(rgIf);
126 private Matcher mtIf;
129 * #foreach(${object in list} direction:"row|col" style:"copy|^copy" shift:"true|false" block:"true|false" start:"number" end:"number" rows:"number" cols:"number")
131 private final String rgForeach = "#foreach\\(\\s*(\\$\\{\\s*\\S+\\s+in\\s+\\S+\\s*\\})(?:\\s+(?:(direction\\s*:\\s*\"[^\"]*\")|(style\\s*:\\s*\"[^\"]*\")|(shift\\s*:\\s*\"[^\"]*\")|(block\\s*:\\s*\"[^\"]*\")|(start\\s*:\\s*\"[^\"]*\")|(end\\s*:\\s*\"[^\"]*\")|(rows\\s*:\\s*\"\\d+\")|(cols\\s*:\\s*\"\\d+\"))){0,8}\\s*\\)";
132 private final Pattern ptForeach = Pattern.compile(rgForeach);
133 private Matcher mtForeach;
138 private final String rgAttrEL = "\\$\\{([^\\{\\}]*)\\}";
139 private final String rgAttr = "\\s*:\\s*\"([^\"]*)\"";
140 private final String $1 = "$1";
145 private final Pattern ptAll = Pattern.compile(rgIf + "|" + rgForeach + "|" + rgEl);
146 private Matcher mtAll = null;
151 private final String[] DATE_FORMATS = {
152 "yyyy-MM-dd'T'HH:mm:ss.SSSXXX",
153 "yyyy-MM-dd'T'HH:mm:ss.SSXXX",
154 "yyyy-MM-dd'T'HH:mm:ss.SXXX",
155 "yyyy-MM-dd'T'HH:mm:ss.SSSXX",
156 "yyyy-MM-dd'T'HH:mm:ss.SSXX",
157 "yyyy-MM-dd'T'HH:mm:ss.SXX",
158 "yyyy-MM-dd'T'HH:mm:ss.SXXX",
159 "yyyy-MM-dd'T'HH:mm:ss.SXX",
160 "yyyy-MM-dd'T'HH:mm:ss.SX",
161 "yyyy-MM-dd'T'HH:mm:ssXXX",
162 "yyyy-MM-dd'T'HH:mm:ssXX",
163 "yyyy-MM-dd'T'HH:mm:ssX",
164 "yyyy-MM-dd'T'HH:mm:ss.S",
165 "yyyy-MM-dd'T'HH:mm:ss",
166 "yyyy-MM-dd'T'HH:mm",
167 "yyyy-MM-dd HH:mm:ss.S",
168 "yyyy-MM-dd HH:mm:ss",
171 "yyyy/MM/dd HH:mm:ss.S",
172 "yyyy/MM/dd HH:mm:ss",
176 private final String[] TIME_FORMATS = {
185 * @param context Jaxlsコンテキストオブジェクト
187 public TLParser(JaxcelContext context) {
188 this.context = context;
189 if(this.context != null) {
190 sheet = this.context.getCurrentSheet();
191 elMgr = this.context.getElManager();
196 * EL式、If句、Foreach句のパース
200 * @throws JaxcelInputException 入力例外発生時
202 public void parse(Cell cell) {
203 log.trace("parse start");
207 log.error("ELManager is null");
208 log.trace("parse end");
209 throw new JaxcelInputException("ELManager is null");
216 log.debug("cell is null");
217 log.trace("parse end");
222 if(this.cell == null) {
223 log.debug("start new cell parse");
229 else if(!this.cell.equals(cell)) {
230 log.debug("start new cell parse");
238 log.debug("start repeat cell parse");
244 if(parseCount >= PARSE_MAX) {
245 log.warn("parse repeat count over");
248 log.trace("parse end");
263 switch (cell.getCellType()) {
264 case Cell.CELL_TYPE_STRING:
265 cell.setCellValue(replaceFirst(""));
267 case Cell.CELL_TYPE_FORMULA:
270 cell.setCellFormula(replaceFirst(""));
272 catch(FormulaParseException e) {
273 log.debug("formula set error: {}", e.getMessage(), e);
274 cell.setCellType(Cell.CELL_TYPE_BLANK);
275 cell.setCellType(Cell.CELL_TYPE_STRING);
276 cell.setCellValue(replaceFirst(""));
277 log.debug("set value type: String");
283 else if(isForeach()) {
292 log.debug("not found TL");
297 log.trace("parse end: reParseFlg: {} parseCount: {}", reParseFlg, parseCount);
307 private boolean find() {
308 log.trace("matchTL start");
310 boolean findFlg = false;
313 type = null; // TL式のタイプ
314 expression = null; // EL式
315 rowSpan = SPAN_DEF; // rows
316 colSpan = SPAN_DEF; // cols
317 delete = LEFT; // delete
319 object = null; // object
320 direction = ROW; // direction
321 shift = true; // shift
322 block = true; // block
323 style = COPY; // style
324 start = null; // start
327 String cellVal = null;
330 startRowIdx = cell.getRowIndex();
331 startColIdx = cell.getColumnIndex();
334 // 文字列・計算式の場合は値保持。以外は終了
335 switch(cell.getCellType()){
336 case Cell.CELL_TYPE_STRING:
337 cellVal = cell.getStringCellValue();
338 log.debug("cell[{}] cellType: string value: {}", (new CellReference(cell)).formatAsString(), cellVal);
340 case Cell.CELL_TYPE_FORMULA:
341 cellVal = cell.getCellFormula();
342 log.debug("cell[{}] cellType: formula value: {}", (new CellReference(cell)).formatAsString(), cellVal);
345 log.debug("cell type is not string or formula");
346 log.trace("matchTL end");
351 mtAll = ptAll.matcher(cellVal);
354 matchString = mtAll.group();
355 log.debug("match: {}", matchString);
358 if((mtIf = ptIf.matcher(matchString)).find()) {
359 log.debug("type: {}", TL_IF);
366 for(int i = 1; i <= mtIf.groupCount(); i++) {
367 if(mtIf.group(i) == null) continue;
369 if(mtIf.group(i).startsWith(TLP_EXPR)) {
370 expression = mtIf.group(i).replaceAll(rgAttrEL, $1).trim();
371 log.debug("expression: {}", expression);
373 // delete:"up|left|clear" 削除動作 デフォルト left
374 else if(mtIf.group(i).startsWith(TLP_DELETE)) {
375 delete = mtIf.group(i).replaceAll(TLP_DELETE + rgAttr, $1).trim();
376 log.debug("{}: {}", TLP_DELETE, delete);
377 if(!UP.equalsIgnoreCase(delete) && !LEFT.equalsIgnoreCase(delete) && !CLEAR.equalsIgnoreCase(delete)) {
378 log.debug("{} is illegal argument. set default: {}", TLP_DELETE, LEFT);
382 // blick:"true|false" ブロック範囲で削除操作をするかの指定 デフォルト true
383 else if(mtIf.group(i).startsWith(TLP_BLOCK)) {
384 block = BooleanUtils.toBoolean(mtIf.group(i).replaceAll(TLP_BLOCK + rgAttr, $1).trim());
385 log.debug("{}: {}", TLP_BLOCK, block);
387 // rows:"number" 範囲 デフォルト 1
388 else if(mtIf.group(i).startsWith(TLP_ROWS)) {
389 rowSpan = NumberUtils.toInt(mtIf.group(i).replaceAll(TLP_ROWS + rgAttr, $1).trim());
390 log.debug("{}: {}", TLP_ROWS, rowSpan);
392 log.warn("{} is illegal argument. set default: {}", TLP_ROWS, SPAN_DEF);
396 // cols:"number" 範囲 デフォルト 1
397 else if(mtIf.group(i).startsWith(TLP_COLS)) {
398 colSpan = NumberUtils.toInt(mtIf.group(i).replaceAll(TLP_COLS + rgAttr, $1).trim());
399 log.debug("{}: {}", TLP_COLS, colSpan);
401 log.warn("{} is illegal argument. set default: {}", TLP_COLS, SPAN_DEF);
408 else if((mtForeach = ptForeach.matcher(matchString)).find()) {
409 log.debug("type: {}", TL_FOREACH);
417 for(int i = 1; i <= mtForeach.groupCount(); i++) {
418 if(mtForeach.group(i) == null) continue;
420 if(mtForeach.group(i).startsWith(TLP_EXPR)) {
421 expression = mtForeach.group(i).replaceAll(rgAttrEL, $1).trim();
422 log.debug("expression: {}", expression);
423 tmp = expression.split("\\s+");
424 if(tmp != null && tmp.length == 3) {
427 if(log.isDebugEnabled()) {
428 log.debug("object: {}", object);
429 log.debug("list: {}", list);
433 log.warn("format error: ex) object in list");
436 // direction:"row|col" 繰返し方向 デフォルト row
437 else if(mtForeach.group(i).startsWith(TLP_DIRECTION)) {
438 direction = mtForeach.group(i).replaceAll(TLP_DIRECTION + rgAttr, $1);
439 log.debug("{}: {}", TLP_DIRECTION, direction);
440 if(!ROW.equalsIgnoreCase(direction) && !COL.equalsIgnoreCase(direction)) {
441 log.warn("{} is illegal argument. set default: {}", TLP_DIRECTION, ROW);
445 // shift:"true|false" foreachレンジより後のセルに対するシフト指定 デフォルト false
446 else if(mtForeach.group(i).startsWith(TLP_SHIFT)) {
447 shift = BooleanUtils.toBoolean(mtForeach.group(i).replaceAll(TLP_SHIFT + rgAttr, $1).trim());
448 log.debug("{}: {}", TLP_SHIFT, shift);
450 // blick:"true|false" foreachレンジをブロック範囲で繰り返すかの指定 デフォルト true
451 else if(mtForeach.group(i).startsWith(TLP_BLOCK)) {
452 block = BooleanUtils.toBoolean(mtForeach.group(i).replaceAll(TLP_BLOCK + rgAttr, $1).trim());
453 log.debug("{}: {}", TLP_BLOCK, block);
455 // style:"copy|^copy" foreachレンジのセルスタイルのコピー指定 デフォルト copy
456 else if(mtForeach.group(i).startsWith(TLP_STYLE)) {
457 style = mtForeach.group(i).replaceAll(TLP_STYLE + rgAttr, $1).trim();
458 log.debug("{}: {}", TLP_STYLE, style);
460 // start:"numberExpression"
461 else if(mtForeach.group(i).startsWith(TLP_START)) {
462 start = mtForeach.group(i).replaceAll(TLP_START + rgAttr, $1);
463 log.debug("{}: {}", TLP_START, start);
465 // end:"numberExpression"
466 else if(mtForeach.group(i).startsWith(TLP_END)) {
467 end = mtForeach.group(i).replaceAll(TLP_END + rgAttr, $1);
468 log.debug("{}: {}", TLP_END, end);
470 // rows:"number" 範囲 デフォルト 1
471 else if(mtForeach.group(i).startsWith(TLP_ROWS)) {
472 rowSpan = NumberUtils.toInt(mtForeach.group(i).replaceAll(TLP_ROWS + rgAttr, $1).trim());
473 log.debug("{}: {}", TLP_ROWS, rowSpan);
475 log.warn("{} is illegal argument. set default: {}", TLP_ROWS, SPAN_DEF);
479 // cols:"number" 範囲 デフォルト 1
480 else if(mtForeach.group(i).startsWith(TLP_COLS)) {
481 colSpan = NumberUtils.toInt(mtForeach.group(i).replaceAll(TLP_COLS + rgAttr, $1).trim());
482 log.debug("{}: {}", TLP_COLS, colSpan);
484 log.warn("{} is illegal argument. set default: {}", TLP_COLS, SPAN_DEF);
491 else if((mtEl = ptEl.matcher(matchString)).find()) {
492 log.debug("type: {}", EL);
499 expression = mtEl.group(1).trim();
500 log.debug("expression: {}", expression);
504 log.warn("TL type: ???");
510 log.debug("unmatch");
513 log.trace("matchTL end: {}", findFlg);
520 private void evaluate() {
521 log.trace("evaluate start");
523 Object elResult; // パース結果保持用
524 String newCellVal; // セル値
527 elResult = elMgr.evaluate(expression);
528 if(elResult == null) {
529 log.debug("evaluate result is null");
532 log.debug("evaluate result: {}", elResult.toString());
534 // マッチ1件目をevaluate結果で置換
535 newCellVal = replaceFirst(elResult == null ? "" : elResult.toString());
536 log.debug("replace value: {}", newCellVal);
538 // newCellValが空白でないなら
539 if(!"".equals(newCellVal.trim())) {
542 if(NumberUtils.isNumber(newCellVal)) {
543 // もともと文字列セルなら数値セルに変更し値をセット
544 if(cell.getCellType() == Cell.CELL_TYPE_STRING) {
545 cell.setCellType(Cell.CELL_TYPE_BLANK);
546 cell.setCellType(Cell.CELL_TYPE_NUMERIC);
549 cell.setCellValue(Integer.parseInt(newCellVal));
550 log.debug("set value type: Integer");
553 catch(NumberFormatException e) {
554 cell.setCellValue(NumberUtils.toDouble(newCellVal));
555 log.debug("set value type: Double");
558 // もともと計算式セルの場合は計算式として値をセット
562 cell.setCellFormula(newCellVal);
563 log.debug("set value type: Formula");
566 catch(FormulaParseException e) {
567 log.warn("formula set error: {}", e.getMessage(), e);
568 cell.setCellType(Cell.CELL_TYPE_BLANK);
569 cell.setCellType(Cell.CELL_TYPE_NUMERIC);
572 cell.setCellValue(Integer.parseInt(newCellVal));
573 log.debug("set value type: Integer");
576 catch(NumberFormatException e2) {
577 cell.setCellValue(NumberUtils.toDouble(newCellVal));
578 log.debug("set value type: Double");
586 else if(StringUtils.equalsIgnoreCase(newCellVal, "true") || StringUtils.equalsIgnoreCase(newCellVal, "false")) {
587 // もともと文字列セルならBoolセルに変更し値をセット
588 if(cell.getCellType() == Cell.CELL_TYPE_STRING) {
589 cell.setCellType(Cell.CELL_TYPE_BLANK);
590 cell.setCellType(Cell.CELL_TYPE_BOOLEAN);
591 cell.setCellValue(BooleanUtils.toBoolean(newCellVal));
592 log.debug("set value type: Boolean");
594 // もともと計算式セルの場合は計算式として値をセット
598 cell.setCellFormula(newCellVal);
599 log.debug("set value type: Formula");
602 catch(FormulaParseException e) {
603 log.warn("formula set error: {}", e.getMessage(), e);
604 cell.setCellType(Cell.CELL_TYPE_BLANK);
605 cell.setCellType(Cell.CELL_TYPE_BOOLEAN);
606 cell.setCellValue(BooleanUtils.toBoolean(newCellVal));
607 log.debug("set value type: Boolean");
617 for(int i = 0; i < 3; i++) {
622 tmpDate = DateUtils.parseDateStrictly(newCellVal, Locale.getDefault(), DATE_FORMATS);
624 } catch (ParseException e1) {}
629 tmpDate = DateUtils.parseDateStrictly(newCellVal, TIME_FORMATS);
631 } catch (ParseException e1) {}
638 if(valType >= 0) break;
645 // もともと文字列セルなら数値セルに変更し値をセット
646 if(cell.getCellType() == Cell.CELL_TYPE_STRING) {
647 cell.setCellType(Cell.CELL_TYPE_BLANK);
648 cell.setCellType(Cell.CELL_TYPE_NUMERIC);
650 if(FORMAT_GENERAL == cell.getCellStyle().getDataFormat() || FORMAT_TEXT == cell.getCellStyle().getDataFormat()) {
651 cell.setCellValue(newCellVal);
652 log.debug("set value type: String");
657 // 置換後の値が日付・日付時刻型ならDateでセット
658 cell.setCellValue(tmpDate);
659 log.debug("set value type: Date");
662 // 置換後の値が時刻型ならDoubleでセット(デフォルトタイムゾーン分加算)
663 cell.setCellValue((tmpDate.getTime() + TimeZone.getDefault().getRawOffset()) / (1000.0 * 60 * 60 * 24));
664 log.debug("set value type: double");
669 // もともと計算式セルの場合は計算式として値をセット
673 cell.setCellFormula(newCellVal);
674 log.debug("set value type: Formula");
677 catch(FormulaParseException e) {
678 log.warn("formula set error: {}", e.getMessage(), e);
679 cell.setCellType(Cell.CELL_TYPE_BLANK);
680 cell.setCellType(Cell.CELL_TYPE_NUMERIC);
681 cell.setCellValue(tmpDate);
682 log.debug("set value type: Date");
689 // 置換後の値が日付・日付時刻・時刻型以外(文字列と判断)
691 if(cell.getCellType() == Cell.CELL_TYPE_STRING) {
692 cell.setCellValue(newCellVal);
693 log.debug("set value type: String");
698 cell.setCellFormula(newCellVal);
699 log.debug("set value type: Formula");
701 catch(FormulaParseException e2) {
702 log.warn("formula set error: {}", e2.getMessage(), e2);
703 cell.setCellType(Cell.CELL_TYPE_BLANK);
704 cell.setCellType(Cell.CELL_TYPE_STRING);
705 cell.setCellValue(newCellVal);
706 log.debug("set value type: String");
716 cell.setCellType(Cell.CELL_TYPE_BLANK);
721 log.trace("evaluate end");
727 private void parseForeach() {
728 log.trace("parseForeach start");
731 Cell fromCell, toCell;
734 Object[] mapKeys = null;
736 ArrayList<CellRangeAddress> rangeList = new ArrayList<>();
737 CellRangeAddress fromRange, toRange, tmpBfRange, tmpAfRange;
740 listObject = elMgr.evaluate(list);
741 if(listObject == null) {
742 log.debug("list is null eval response.");
743 log.trace("parseForeach end");
746 log.debug("list class: {}", listObject.getClass().getName());
748 // listObject Mapならキー取得
749 if(listObject instanceof Map) {
750 mapKeys = ((Map<?, ?>)listObject).keySet().toArray();
754 evalObject = elMgr.evaluate("size(" + list + ")");
755 // evalした結果がintでなければリスト不可なオブジェクトと判断
756 if(evalObject == null) {
757 log.error("list size unknown");
758 log.trace("parseForeach end");
761 else if(!(evalObject instanceof Integer)) {
762 log.error("list size is not Integer instance");
763 log.trace("parseForeach end");
766 listSize = (int) evalObject;
767 log.debug("list size: {}", listSize);
772 log.debug("start: {}", start);
773 // size(list) 等 式の可能性もあるのでevalする
774 evalObject = elMgr.evaluate(start);
775 if(evalObject != null) {
776 // evalした結果がintでなければデフォルト
777 if(!(evalObject instanceof Integer)) {
778 log.warn("start is not Integer instance. start set default: {}", IDX_BASE);
782 startIdx = (int) evalObject;
785 // startIdxが0の場合、1に補正
788 else if(startIdx < 0) {
789 // startIdxがマイナス値の場合、listのサイズからの逆順とする
791 startIdx = listSize + startIdx + IDX_BASE;
793 else if(startIdx > listSize) {
794 // startIdxがリストのサイズより大きい場合、リストのサイズに切り詰める
799 // evalした結果がnullの場合はデフォルト
801 log.debug("start is null eval response. start set default: {}", IDX_BASE);
806 log.debug("start is null. start set default: {}", IDX_BASE);
809 log.debug("startIdx: {}", startIdx);
814 log.debug("end: {}", end);
815 // size(list) 等 式の可能性もあるのでevalする
816 evalObject = elMgr.evaluate(end);
817 if(evalObject != null) {
818 // evalした結果がintでなければリストサイズ
819 if(!(evalObject instanceof Integer)) {
820 log.warn("end is not Integer instance. end set list size: {}", listSize);
824 endIdx = (int) evalObject;
827 // endIdxが0の場合、リストサイズ
830 else if(endIdx < 0) {
831 // endIdxがマイナス値の場合、listのサイズからの逆順とする
833 endIdx = listSize + endIdx + IDX_BASE;
835 else if(endIdx > listSize) {
836 // endIdxがリストのサイズより大きい場合、リストのサイズに切り詰める
841 // evalした結果がnullの場合はリストサイズ
843 log.debug("end is null eval response. end set list size: {}", listSize);
848 log.debug("end is null. end set list size: {}", listSize);
852 if(log.isDebugEnabled()) {
853 log.debug("endIdx: {}", endIdx);
854 log.debug("direction: {}", direction);
855 log.debug("shift: {}", shift);
856 log.debug("block: {}", block);
857 log.debug("style: {}", style);
860 // コピー元範囲 block:falseの場合、行・列全体に範囲を広げる
862 // 繰返し方向横(列)(行がデフォルト)
863 if(COL.equalsIgnoreCase(direction)) {
864 fromRange = new CellRangeAddress(sheet.getFirstRowNum(), sheet.getLastRowNum(), startColIdx, startColIdx + colSpan - 1);
868 fromRange = new CellRangeAddress(startRowIdx, startRowIdx + rowSpan - 1, 0, ExcelUtil.getLastColNum(sheet));
872 fromRange = new CellRangeAddress(startRowIdx, startRowIdx + rowSpan - 1, startColIdx, startColIdx + colSpan - 1);
875 fromRange = ExcelUtil.getIntersectRange(sheet, fromRange);
877 // 繰返しコピー回数1以上なら、コピー先範囲シフト・クリア等実施
878 if(startIdx != endIdx) {
880 int copyCount = startIdx < endIdx ? endIdx - startIdx : startIdx - endIdx;
881 // 繰返し方向横(列)(行がデフォルト)
882 if(COL.equalsIgnoreCase(direction)) {
883 toRange = new CellRangeAddress(
884 fromRange.getFirstRow(),
885 fromRange.getLastRow(),
886 fromRange.getLastColumn() + 1,
887 fromRange.getLastColumn() + (fromRange.getLastColumn() - fromRange.getFirstColumn() + 1) * copyCount);
891 toRange = new CellRangeAddress(
892 fromRange.getLastRow() + 1,
893 fromRange.getLastRow() + (fromRange.getLastRow() - fromRange.getFirstRow() + 1) * copyCount,
894 fromRange.getFirstColumn(),
895 fromRange.getLastColumn());
898 // shift:trueの場合、コピー先範囲の後続範囲をシフト
901 int distance = (startIdx > endIdx ? startIdx - endIdx : endIdx - startIdx);
903 // 繰返し方向横(列)(行がデフォルト)
904 if(COL.equalsIgnoreCase(direction)) {
907 ExcelUtil.shift(sheet, new CellRangeAddress(fromRange.getFirstRow(), fromRange.getLastRow(), fromRange.getLastColumn() + 1, fromRange.getLastColumn() + 1), COL, distance, block);
913 ExcelUtil.shift(sheet, new CellRangeAddress(fromRange.getLastRow() + 1, fromRange.getLastRow() + 1, fromRange.getFirstColumn(), fromRange.getLastColumn()), ROW, distance, block);
916 // shift:falseの場合、コピー先範囲をクリア
918 ExcelUtil.clearRange(sheet, toRange, COPY.equalsIgnoreCase(style), COPY.equalsIgnoreCase(style));
920 // style:copyの場合、コピー元範囲の結合保持・解除
921 if(COPY.equalsIgnoreCase(style)) {
922 // コピー元範囲の結合状態チェック・保持。コピー先範囲の結合解除
923 CellRangeAddress tmpRange;
924 for(int i = 0; i < sheet.getNumMergedRegions(); i++) {
925 tmpRange = sheet.getMergedRegion(i);
927 switch(CellRangeUtil.intersect(fromRange, tmpRange)) {
928 case CellRangeUtil.INSIDE:
929 rangeList.add(tmpRange);
930 log.debug("from range inside mergedRegion. save: {}", tmpRange.formatAsString());
932 case CellRangeUtil.ENCLOSES:
933 log.warn("from range encloses mergedRegion. remove: {}", tmpRange.formatAsString());
934 sheet.removeMergedRegion(i);
936 case CellRangeUtil.OVERLAP:
937 log.warn("from range overlap mergedRegion. remove: {}", tmpRange.formatAsString());
938 sheet.removeMergedRegion(i);
946 boolean copyFlg = true;
947 for(int i = startIdx, cpCount = 0; (startIdx <= endIdx && i <= endIdx || startIdx > endIdx && i >= endIdx); i = (startIdx <= endIdx ? i + 1 : i - 1), cpCount++) {
949 for(int r = fromRange.getFirstRow(); r <= fromRange.getLastRow(); r++) {
950 // 繰返し方向縦(行)の場合、コピー先の範囲チェック
951 if(ROW.equalsIgnoreCase(direction) && (r + rowSpan * cpCount < 0 || r + rowSpan * cpCount > ExcelUtil.getMaxRowIndex(sheet))) {
953 log.warn("to row outside sheet");
960 fromRow = sheet.getRow(r);
962 toRow = ROW.equalsIgnoreCase(direction) ? sheet.getRow(r + rowSpan * cpCount) : fromRow;
964 // コピー元行がnullならコピー先行もnull。continue
965 if(fromRow == null) {
967 log.debug("continue. from row [{}] is null. to row [{}] remove", (r + 1), (toRow.getRowNum() + 1));
968 sheet.removeRow(toRow);
971 log.debug("continue. from row [{}] and to row [{}] is null", (r + 1), ((ROW.equalsIgnoreCase(direction) ? (r + rowSpan * cpCount) : r) + 1));
977 if(toRow == null) toRow = sheet.createRow(r + rowSpan * cpCount);
979 // コピー元行・コピー先行 行番号が異なり、block falseなら行情報(高さ)もコピー
980 if(fromRow.getRowNum() != toRow.getRowNum() && !block) toRow.setHeight(fromRow.getHeight());
983 for(int c = fromRange.getFirstColumn(); c <= fromRange.getLastColumn(); c++) {
984 // 繰返し方向横(列)の場合、コピー先の範囲チェック
985 if(COL.equalsIgnoreCase(direction) && (c + colSpan * cpCount < 0 || c + colSpan * cpCount > ExcelUtil.getMaxColumnIndex(sheet))) {
987 log.warn("to cell outside sheet");
992 fromCell = fromRow.getCell(c);
994 toCell = toRow.getCell(COL.equalsIgnoreCase(direction) ? c + colSpan * cpCount : c);
996 // コピー元セルがnullならコピー先セルもnull
997 if(fromCell == null) {
999 log.debug("continue. from cell [{}] is null. to cell [{}] remove", (new CellReference(fromRow.getRowNum(), c)).formatAsString(), (new CellReference(toCell.getRowIndex(), toCell.getColumnIndex())).formatAsString());
1000 toRow.removeCell(toCell);
1003 log.debug("continue. from cell [{}] and to cell [{}] is null", (new CellReference(fromRow.getRowNum(), c)).formatAsString(), (new CellReference(toRow.getRowNum(), COL.equalsIgnoreCase(direction) ? c + colSpan * cpCount : c)).formatAsString());
1009 if(toCell == null) toCell = toRow.createCell(COL.equalsIgnoreCase(direction) ? c + colSpan * cpCount : c);
1011 // コピー元列・コピー先列 列番号が異なり、block falseなら列情報(幅)もコピー ( 繰返しループ1回目のみ)
1012 if(cpCount == 0 && fromCell.getColumnIndex() != toCell.getColumnIndex() && !block)
1013 sheet.setColumnWidth(toCell.getColumnIndex(), sheet.getColumnWidth(fromCell.getColumnIndex()));
1016 if(cpCount > 0 && COPY.equalsIgnoreCase(style)) {
1018 toCell.setCellStyle(fromCell.getCellStyle());
1021 switch(fromCell.getCellType()) {
1022 case Cell.CELL_TYPE_BLANK:
1023 toCell.setCellType(Cell.CELL_TYPE_BLANK);
1025 case Cell.CELL_TYPE_BOOLEAN:
1026 toCell.setCellType(Cell.CELL_TYPE_BOOLEAN);
1027 toCell.setCellValue(fromCell.getBooleanCellValue());
1029 case Cell.CELL_TYPE_ERROR:
1030 toCell.setCellType(Cell.CELL_TYPE_ERROR);
1031 toCell.setCellErrorValue(fromCell.getErrorCellValue());
1033 case Cell.CELL_TYPE_FORMULA:
1034 toCell.setCellType(Cell.CELL_TYPE_FORMULA);
1036 toCell.setCellFormula(
1037 ExcelUtil.getMoveFormula(
1039 fromCell.getCellFormula().replace(
1040 (cpCount == 0 ? object : list + "[" + (mapKeys == null ? (startIdx - 1) : "'" + mapKeys[startIdx - 1] + "'") + "]"), list + "[" + (mapKeys == null ? (i - 1) : "'" + mapKeys[i - 1] + "'") + "]"),
1041 toCell.getRowIndex() - fromCell.getRowIndex(),
1042 toCell.getColumnIndex() - fromCell.getColumnIndex()
1045 log.debug("to cell Formula: {}", toCell.getCellFormula());
1047 case Cell.CELL_TYPE_NUMERIC:
1048 toCell.setCellType(Cell.CELL_TYPE_NUMERIC);
1049 toCell.setCellValue(fromCell.getNumericCellValue());
1051 case Cell.CELL_TYPE_STRING:
1052 toCell.setCellType(Cell.CELL_TYPE_STRING);
1053 toCell.setCellValue(fromCell.getStringCellValue().replace((cpCount == 0 ? object : list + "[" + (mapKeys == null ? (startIdx - 1) : "'" + mapKeys[startIdx - 1] + "'") + "]"), list + "[" + (mapKeys == null ? (i - 1) : "'" + mapKeys[i - 1] + "'") + "]"));
1054 log.debug("to cell string: {}", toCell.getStringCellValue());
1059 // 繰返しコピーフラグfalseならbreak
1064 // for(int r = fromRange.getFirstRow(); r <= fromRange.getLastRow(); r++) {
1065 // row = sheet.getRow(r);
1066 // // コピー元行がnullで繰返し方向横(列)の場合
1067 // if(row == null && COL.equalsIgnoreCase(direction)) {
1068 // // コピー先行もnullとなるのでセルの処理はせず終了
1069 // log.debug("continue. direction: col from row [{}] is null", (r + 1));
1074 // for(int c = fromRange.getFirstColumn(); c <= fromRange.getLastColumn(); c++) {
1075 // // コピー元行がnullの場合セルもnull
1076 // if(row == null) {
1079 // cell = row.getCell(c);
1083 // for(int i = startIdx, cpCount = 0; (startIdx <= endIdx && i <= endIdx || startIdx > endIdx && i >= endIdx); i = (startIdx <= endIdx ? i + 1 : i - 1), cpCount++) {
1084 // // 繰返し方向横(列)(行がデフォルト)
1085 // if(COL.equalsIgnoreCase(direction)) {
1087 // if(c + colSpan * cpCount < 0 || c + colSpan * cpCount > ExcelUtil.getMaxColumnIndex(sheet)) {
1088 // log.warn("to cell outside sheet");
1092 // toCell = row.getCell(c + colSpan * cpCount);
1093 // // コピー元セルがnullならコピー先セルもnull
1094 // if(cell == null) {
1095 // if(toCell != null) {
1096 // toRow.removeCell(toCell);
1097 // log.debug("continue. from cell [{}] is null. to cell [{}] remove", (new CellReference(r, c)).formatAsString(), (new CellReference(r, c + colSpan * cpCount)).formatAsString());
1100 // log.debug("continue. from cell [{}] and to cell [{}] is null", (new CellReference(r, c)).formatAsString(), (new CellReference(r, c + colSpan * cpCount)).formatAsString());
1105 // if(toCell == null) toCell = row.createCell(c + colSpan * cpCount);
1106 // // block falseなら列情報(幅)もコピー
1108 // sheet.setColumnWidth(toCell.getColumnIndex(), sheet.getColumnWidth(cell.getColumnIndex()));
1115 // if(r + rowSpan * cpCount < 0 || r + rowSpan * cpCount > ExcelUtil.getMaxRowIndex(sheet)) {
1116 // log.warn("to row outside sheet");
1120 // toRow = sheet.getRow(r + rowSpan * cpCount);
1122 // // コピー元行がnullならコピー先行もnull
1123 // if(row == null) {
1124 // if(toRow != null) {
1125 // sheet.removeRow(toRow);
1126 // log.debug("continue. from row [{}] is null. to row [{}] remove", (r + 1));
1129 // log.debug("continue. from and to row is null");
1134 // if(toRow == null) toRow = sheet.createRow(r + rowSpan * cpCount);
1135 // // block falseなら行情報(高さ)もコピー
1137 // toRow.setHeight(row.getHeight());
1139 // toCell = toRow.getCell(c);
1140 // // コピー元セルがnullならコピー先セルもnull
1141 // if(cell == null) {
1142 // if(toCell != null) {
1143 // toRow.removeCell(toCell);
1144 // log.debug("continue. from cell is null. to cell remove");
1147 // log.debug("continue. from cell [{}] and to cell [{}] is null", (new CellReference(r, c)).formatAsString(), (new CellReference(r + rowSpan * cpCount, c)).formatAsString());
1152 // if(toCell == null) toCell = toRow.createCell(c);
1158 // if(cpCount > 0 && COPY.equalsIgnoreCase(style)) {
1160 // toCell.setCellStyle(cell.getCellStyle());
1163 // switch(cell.getCellType()) {
1164 // case Cell.CELL_TYPE_BLANK:
1165 // toCell.setCellType(Cell.CELL_TYPE_BLANK);
1167 // case Cell.CELL_TYPE_BOOLEAN:
1168 // toCell.setCellType(Cell.CELL_TYPE_BOOLEAN);
1169 // toCell.setCellValue(cell.getBooleanCellValue());
1171 // case Cell.CELL_TYPE_ERROR:
1172 // toCell.setCellType(Cell.CELL_TYPE_ERROR);
1173 // toCell.setCellErrorValue(cell.getErrorCellValue());
1175 // case Cell.CELL_TYPE_FORMULA:
1176 // toCell.setCellType(Cell.CELL_TYPE_FORMULA);
1177 // // 数式のパース・移動先に合わせる
1178 // toCell.setCellFormula(
1179 // ExcelUtil.getMoveFormula(
1181 // cell.getCellFormula().replace(
1182 // (i == startIdx ? object : list + "[" + (mapKeys == null ? (startIdx - 1) : "'" + mapKeys[startIdx - 1] + "'") + "]"), list + "[" + (mapKeys == null ? (i - 1) : "'" + mapKeys[i - 1] + "'") + "]"),
1183 // toCell.getRowIndex() - cell.getRowIndex(),
1184 // toCell.getColumnIndex() - cell.getColumnIndex()
1187 // log.debug("to cell Formula: {}", toCell.getCellFormula());
1189 // case Cell.CELL_TYPE_NUMERIC:
1190 // toCell.setCellType(Cell.CELL_TYPE_NUMERIC);
1191 // toCell.setCellValue(cell.getNumericCellValue());
1193 // case Cell.CELL_TYPE_STRING:
1194 // toCell.setCellType(Cell.CELL_TYPE_STRING);
1195 // toCell.setCellValue(cell.getStringCellValue().replace((i == startIdx ? object : list + "[" + (mapKeys == null ? (startIdx - 1) : "'" + mapKeys[startIdx - 1] + "'") + "]"), list + "[" + (mapKeys == null ? (i - 1) : "'" + mapKeys[i - 1] + "'") + "]"));
1196 // log.debug("to cell string: {}", toCell.getStringCellValue());
1203 if(COPY.equalsIgnoreCase(style)) {
1207 if(COL.equalsIgnoreCase(direction)) {
1215 if(!rangeList.isEmpty()) {
1218 for(int c = 0; c < rangeList.size(); c++) {
1219 tmpBfRange = rangeList.get(c);
1221 for(int i = startIdx, cpCount = 0; (startIdx <= endIdx && i <= endIdx || startIdx > endIdx && i >= endIdx); i = (startIdx <= endIdx ? i + 1 : i - 1), cpCount++) {
1222 // 初回はコピーしない(コピー元だから)
1223 if(i == startIdx) continue;
1225 tmpAfRange = new CellRangeAddress(
1226 tmpBfRange.getFirstRow() + (addRow * cpCount),
1227 tmpBfRange.getLastRow() + (addRow * cpCount),
1228 tmpBfRange.getFirstColumn() + (addCol * cpCount),
1229 tmpBfRange.getLastColumn() + (addCol * cpCount));
1230 if(ExcelUtil.validateRange(sheet, tmpAfRange)) {
1231 sheet.addMergedRegion(tmpAfRange);
1232 log.debug("mergedRegion copy. from: [{}] to: [{}]", tmpBfRange.formatAsString(), tmpAfRange.formatAsString());
1240 if(sheet instanceof HSSFSheet) {
1241 CellRangeAddress cpRange;
1243 HSSFPatriarch patriarch = ((HSSFSheet)sheet).getDrawingPatriarch();
1244 if(patriarch != null) {
1245 List<HSSFShape> shapes = ((HSSFSheet)sheet).getDrawingPatriarch().getChildren();
1246 if(shapes != null) {
1247 HSSFClientAnchor fAnchor, tAnchor;
1251 for (int i = 0; i < shapes.size(); i++) {
1252 fAnchor = (HSSFClientAnchor)shapes.get(i).getAnchor();
1253 if(fAnchor != null) {
1254 r1 = fAnchor.getRow1();
1255 c1 = fAnchor.getCol1();
1256 r2 = fAnchor.getRow2();
1257 c2 = fAnchor.getCol2();
1258 tmpRange = new CellRangeAddress(r1, r2, c1, c2);
1259 switch(CellRangeUtil.intersect(fRange, tmpRange)) {
1260 case CellRangeUtil.INSIDE:
1261 case CellRangeUtil.OVERLAP:
1263 if(!ROW.equalsIgnoreCase(direction)) {
1264 tAnchor = new HSSFClientAnchor(
1265 fAnchor.getDx1(), fAnchor.getDy1(),
1266 fAnchor.getDx2(), fAnchor.getDy2(),
1267 (short) (c1 + (colSpan * cpCount)), r1,
1268 (short) (c2 + (colSpan * cpCount)), r2);
1269 cpRange = new CellRangeAddress(r1, r2, c1 + (colSpan * cpCount), c2 + (colSpan * cpCount));
1273 tAnchor = new HSSFClientAnchor(
1274 fAnchor.getDx1(), fAnchor.getDy1(),
1275 fAnchor.getDx2(), fAnchor.getDy2(),
1276 c1, r1 + (rowSpan * cpCount),
1277 c2, r2 + (rowSpan * cpCount));
1278 cpRange = new CellRangeAddress(r1 + (rowSpan * cpCount), r2 + (rowSpan * cpCount), c1, c2);
1280 if(log.isDebugEnabled()) log.debug("object copy from: " + tmpRange.formatAsString() + " to: " + cpRange.formatAsString());
1282 patriarch.addShape(new shapes.get(i),)
1290 // オブジェクトのコピー Excel2007以降 ooxml形式のみ対応
1291 if(sheet instanceof XSSFSheet) {
1293 CTDrawing ctDrawing;
1294 CTTwoCellAnchor fAnchor, cpAnchor;
1298 for(POIXMLDocumentPart part : ((XSSFSheet)sheet).getRelations()) {
1299 if(part == null) continue;
1300 log.debug("DocumentPart class: {}", part.getClass().getName());
1301 // DocumentPartがDrawingオブジェクトの場合
1302 if(part instanceof XSSFDrawing) {
1303 ctDrawing = ((XSSFDrawing) part).getCTDrawing();
1304 if(ctDrawing != null) {
1306 int alSize = ctDrawing.getTwoCellAnchorList().size();
1307 for (int i = 0; i < alSize; i++) {
1308 fAnchor = ctDrawing.getTwoCellAnchorList().get(i);
1309 // GraphicFrameをもつグラフ、スマートアートは簡単にはコピーできないので非対応
1310 if(fAnchor.isSetGraphicFrame()) continue;
1313 from = fAnchor.getFrom();
1316 to = fAnchor.getTo();
1319 tmpBfRange = new CellRangeAddress(r1, r2, c1, c2);
1321 // コピー元レンジに含まれている、掛かっているならコピー
1322 switch(CellRangeUtil.intersect(fromRange, tmpBfRange)) {
1323 case CellRangeUtil.INSIDE:
1324 case CellRangeUtil.OVERLAP:
1326 for(int j = startIdx, cpCount = 0; (startIdx <= endIdx && j <= endIdx || startIdx > endIdx && j >= endIdx); j = (startIdx <= endIdx ? j + 1 : j - 1), cpCount++) {
1327 // 初回はコピーしない(コピー元だから)
1328 if(j == startIdx) continue;
1330 cpAnchor = ctDrawing.addNewTwoCellAnchor();
1331 cpAnchor.set(fAnchor.copy());
1332 from = cpAnchor.getFrom();
1333 from.setRow(from.getRow() + (addRow * cpCount));
1334 from.setCol(from.getCol() + (addCol * cpCount));
1335 to = cpAnchor.getTo();
1336 to.setRow(to.getRow() + (addRow * cpCount));
1337 to.setCol(to.getCol() + (addCol * cpCount));
1338 if(log.isDebugEnabled()) {
1339 tmpAfRange = new CellRangeAddress(from.getRow(), to.getRow(), from.getCol(), to.getCol());
1340 log.debug("object copy from: [{}] to: [{}]", tmpBfRange.formatAsString(), tmpAfRange.formatAsString());
1349 catch(Exception e) {
1350 log.error("object copy error: " + e.getMessage(), e);
1354 log.trace("parseForeach end");
1360 private void parseIf() {
1361 log.trace("parseIf start");
1365 Object elResult = elMgr.evaluate(expression);
1366 if(elResult == null) {
1367 log.debug("evaluate result is null");
1370 else if(elResult instanceof Boolean) {
1371 result = (boolean) elResult;
1376 log.debug("evaluate result: {}", result);
1380 if(delete == null) {
1381 log.debug("{} is null set default: {}", TLP_DELETE, LEFT);
1384 else if(!LEFT.equalsIgnoreCase(delete) && !UP.equalsIgnoreCase(delete) && !CLEAR.equalsIgnoreCase(delete)) {
1385 log.warn("{} is illegal argument. set default: {}", TLP_DELETE, LEFT);
1389 log.debug("delete: {}", delete);
1390 delete = delete.toLowerCase().trim();
1396 ExcelUtil.clearRange(sheet, (new CellRangeAddress(startRowIdx, startRowIdx + rowSpan - 1, startColIdx, startColIdx + colSpan - 1)), false, false);
1401 ExcelUtil.shift(sheet, new CellRangeAddress(startRowIdx, startRowIdx + rowSpan - 1, startColIdx + colSpan, startColIdx + colSpan), COL, -colSpan, block);
1406 ExcelUtil.shift(sheet, new CellRangeAddress(startRowIdx + rowSpan, startRowIdx + rowSpan, startColIdx, startColIdx + colSpan - 1), ROW, -rowSpan, block);
1409 log.trace("parseIf end");
1413 * マッチした結果がEL式であるかを返却
1415 * @return マッチした結果がEL式であればtrue。以外の場合false
1417 private boolean isEL() {
1418 return EL.equalsIgnoreCase(type);
1422 * マッチした結果がIf句であるかを返却
1424 * @return マッチした結果がIf句であればtrue。以外の場合false
1426 private boolean isIf() {
1427 return TL_IF.equalsIgnoreCase(type);
1431 * マッチした結果がForeach句であるかを返却
1433 * @return マッチした結果がForeach句であればtrue。以外の場合false
1435 private boolean isForeach() {
1436 return TL_FOREACH.equalsIgnoreCase(type);
1440 * 指示子全体検索結果から1つ目の指示子を置換
1442 * @param replacement 置換文字列
1446 private String replaceFirst(String replacement) {
1447 return mtAll.replaceFirst(replacement == null ? "" : replacement);
1453 * @return 再パース必要であればはtrue。不要であればfalse
1455 public boolean isReParseCell() {