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;
24 import java.util.regex.Matcher;
25 import java.util.regex.Pattern;
28 import org.apache.commons.lang3.BooleanUtils;
29 import org.apache.commons.lang3.StringUtils;
30 import org.apache.commons.lang3.math.NumberUtils;
31 import org.apache.commons.lang3.time.DateUtils;
32 import org.apache.poi.POIXMLDocumentPart;
33 import org.apache.poi.hssf.record.cf.CellRangeUtil;
34 import org.apache.poi.ss.formula.FormulaParseException;
35 import org.apache.poi.ss.usermodel.Cell;
36 import org.apache.poi.ss.usermodel.Row;
37 import org.apache.poi.ss.usermodel.Sheet;
38 import org.apache.poi.ss.util.CellRangeAddress;
39 import org.apache.poi.ss.util.CellReference;
40 import org.apache.poi.xssf.usermodel.XSSFDrawing;
41 import org.apache.poi.xssf.usermodel.XSSFSheet;
42 import org.hanei.jaxcel.exception.JaxcelInputException;
43 import org.hanei.jaxcel.util.ExcelUtil;
44 import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing;
45 import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
46 import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor;
47 import org.slf4j.LoggerFactory;
48 import org.slf4j.Logger;
51 * Excelテンプレートシートの指示子(Template Language)、EL式(Expression Language)の検索、パースを行う
53 * @author Noboru Saito
56 public class TLParser {
58 private static final Logger log = LoggerFactory.getLogger(TLParser.class);
60 private static final String EL = "el";
61 private static final String TL_IF = "if";
62 private static final String TL_FOREACH = "foreach";
63 private static final String TLP_EXPR = "${";
64 private static final String TLP_DELETE = "delete";
65 private static final String TLP_DIRECTION = "direction";
66 private static final String TLP_SHIFT = "shift";
67 private static final String TLP_BLOCK = "block";
68 private static final String TLP_STYLE = "style";
69 private static final String TLP_START = "start";
70 private static final String TLP_END = "end";
71 private static final String TLP_ROWS = "rows";
72 private static final String TLP_COLS = "cols";
74 private static final String LEFT = "left";
75 private static final String UP = "up";
76 private static final String CLEAR = "clear";
77 private static final String ROW = "row";
78 private static final String COL = "col";
79 private static final String COPY = "copy";
80 private static final int SPAN_DEF = 1;
81 private static final int IDX_BASE = 1;
82 private static final int PARSE_MAX = 10;
84 private static final short FORMAT_GENERAL = 0;
86 private Sheet sheet = null;
87 private JaxcelContext context = null;
88 private ELManager elMgr = null;
89 private Cell cell = null;
90 private int startRowIdx;
91 private int startColIdx;
93 private String type; // TL式のタイプ
94 private String expression; // EL式
95 private String delete; // delete
96 private int rowSpan; // row
97 private int colSpan; // column
98 private String direction; // direction
99 private boolean shift; // shift
100 private boolean block; // block
101 private String style; // style
102 private String start; // start
103 private String end; // end
104 private String list; // list
105 private String object; // object
106 private String matchString; // マッチした文字列保持用
107 private boolean reParseFlg; // 同一セル再パース要否フラグ
108 private int parseCount; // 同一セルパース回数
113 private final String rgEl = "\\$\\{([^\\{\\}]+)\\}";
114 private final Pattern ptEl = Pattern.compile(rgEl);
115 private Matcher mtEl;
118 * #if(${expression} delete:"up|left|clear" block:"true|false" rows:"number" cols:"number")
120 private final String rgIf = "#if\\(\\s*(\\$\\{[^\\{\\}]+\\})(?:\\s+(?:(delete\\s*:\\s*\"[^\"]*\")|(block\\s*:\\s*\"[^\"]*\")|(rows\\s*:\\s*\"\\d+\")|(cols\\s*:\\s*\"\\d+\"))){0,4}\\s*\\)";
121 private final Pattern ptIf = Pattern.compile(rgIf);
122 private Matcher mtIf;
125 * #foreach(${object in list} direction:"row|col" style:"copy|^copy" shift:"true|false" block:"true|false" start:"number" end:"number" rows:"number" cols:"number")
127 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*\\)";
128 private final Pattern ptForeach = Pattern.compile(rgForeach);
129 private Matcher mtForeach;
134 private final String rgAttrEL = "\\$\\{([^\\{\\}]*)\\}";
135 private final String rgAttr = "\\s*:\\s*\"([^\"]*)\"";
136 private final String $1 = "$1";
141 private final Pattern ptAll = Pattern.compile(rgIf + "|" + rgForeach + "|" + rgEl);
142 private Matcher mtAll = null;
147 private final String[] DATE_FORMATS = {
150 "yyyy-MM-dd HH:mm:ss.SSS",
151 "yyyy-MM-dd HH:mm:ss",
153 "yyyy/MM/dd HH:mm:ss.SSS",
154 "yyyy/MM/dd HH:mm:ss",
164 * @param context Jaxlsコンテキストオブジェクト
166 public TLParser(JaxcelContext context) {
167 this.context = context;
168 if(this.context != null) {
169 sheet = this.context.getCurrentSheet();
170 elMgr = this.context.getElManager();
175 * EL式、If句、Foreach句のパース
179 * @throws JaxcelInputException 入力例外発生時
181 public void parse(Cell cell) {
182 log.trace("parse start");
186 log.error("ELManager is null");
187 log.trace("parse end");
188 throw new JaxcelInputException("ELManager is null");
195 log.debug("cell is null");
196 log.trace("parse end");
201 if(this.cell == null) {
202 log.debug("start new cell parse");
208 else if(!this.cell.equals(cell)) {
209 log.debug("start new cell parse");
217 log.debug("start repeat cell parse");
223 if(parseCount >= PARSE_MAX) {
224 log.warn("parse repeat count over");
227 log.trace("parse end");
242 switch (cell.getCellType()) {
243 case Cell.CELL_TYPE_STRING:
244 cell.setCellValue(replaceFirst(""));
246 case Cell.CELL_TYPE_FORMULA:
249 cell.setCellFormula(replaceFirst(""));
251 catch(FormulaParseException e) {
252 log.debug("formula set error: {}", e.getMessage(), e);
253 cell.setCellType(Cell.CELL_TYPE_BLANK);
254 cell.setCellType(Cell.CELL_TYPE_STRING);
255 cell.setCellValue(replaceFirst(""));
256 log.debug("set value type: String");
262 else if(isForeach()) {
271 log.debug("not found TL");
276 log.trace("parse end: reParseFlg: {} parseCount: {}", reParseFlg, parseCount);
286 private boolean find() {
287 log.trace("matchTL start");
289 boolean findFlg = false;
292 type = null; // TL式のタイプ
293 expression = null; // EL式
294 rowSpan = SPAN_DEF; // rows
295 colSpan = SPAN_DEF; // cols
296 delete = LEFT; // delete
298 object = null; // object
299 direction = ROW; // direction
300 shift = true; // shift
301 block = true; // block
302 style = COPY; // style
303 start = null; // start
306 String cellVal = null;
309 startRowIdx = cell.getRowIndex();
310 startColIdx = cell.getColumnIndex();
313 // 文字列・計算式の場合は値保持。以外は終了
314 switch(cell.getCellType()){
315 case Cell.CELL_TYPE_STRING:
316 cellVal = cell.getStringCellValue();
317 log.debug("cell[{}] cellType: string value: {}", (new CellReference(cell)).formatAsString(), cellVal);
319 case Cell.CELL_TYPE_FORMULA:
320 cellVal = cell.getCellFormula();
321 log.debug("cell[{}] cellType: formula value: {}", (new CellReference(cell)).formatAsString(), cellVal);
324 log.debug("cell type is not string or formula");
325 log.trace("matchTL end");
330 mtAll = ptAll.matcher(cellVal);
333 matchString = mtAll.group();
334 log.debug("match: {}", matchString);
337 if((mtIf = ptIf.matcher(matchString)).find()) {
338 log.debug("type: {}", TL_IF);
345 for(int i = 1; i <= mtIf.groupCount(); i++) {
346 if(mtIf.group(i) == null) continue;
348 if(mtIf.group(i).startsWith(TLP_EXPR)) {
349 expression = mtIf.group(i).replaceAll(rgAttrEL, $1).trim();
350 log.debug("expression: {}", expression);
352 // delete:"up|left|clear" 削除動作 デフォルト left
353 else if(mtIf.group(i).startsWith(TLP_DELETE)) {
354 delete = mtIf.group(i).replaceAll(TLP_DELETE + rgAttr, $1).trim();
355 log.debug("{}: {}", TLP_DELETE, delete);
356 if(!UP.equalsIgnoreCase(delete) && !LEFT.equalsIgnoreCase(delete) && !CLEAR.equalsIgnoreCase(delete)) {
357 log.debug("{} is illegal argument. set default: {}", TLP_DELETE, LEFT);
361 // blick:"true|false" ブロック範囲で削除操作をするかの指定 デフォルト true
362 else if(mtIf.group(i).startsWith(TLP_BLOCK)) {
363 block = BooleanUtils.toBoolean(mtIf.group(i).replaceAll(TLP_BLOCK + rgAttr, $1).trim());
364 log.debug("{}: {}", TLP_BLOCK, block);
366 // rows:"number" 範囲 デフォルト 1
367 else if(mtIf.group(i).startsWith(TLP_ROWS)) {
368 rowSpan = NumberUtils.toInt(mtIf.group(i).replaceAll(TLP_ROWS + rgAttr, $1).trim());
369 log.debug("{}: {}", TLP_ROWS, rowSpan);
371 log.warn("{} is illegal argument. set default: {}", TLP_ROWS, SPAN_DEF);
375 // cols:"number" 範囲 デフォルト 1
376 else if(mtIf.group(i).startsWith(TLP_COLS)) {
377 colSpan = NumberUtils.toInt(mtIf.group(i).replaceAll(TLP_COLS + rgAttr, $1).trim());
378 log.debug("{}: {}", TLP_COLS, colSpan);
380 log.warn("{} is illegal argument. set default: {}", TLP_COLS, SPAN_DEF);
387 else if((mtForeach = ptForeach.matcher(matchString)).find()) {
388 log.debug("type: {}", TL_FOREACH);
396 for(int i = 1; i <= mtForeach.groupCount(); i++) {
397 if(mtForeach.group(i) == null) continue;
399 if(mtForeach.group(i).startsWith(TLP_EXPR)) {
400 expression = mtForeach.group(i).replaceAll(rgAttrEL, $1).trim();
401 log.debug("expression: {}", expression);
402 tmp = expression.split("\\s+");
403 if(tmp != null && tmp.length == 3) {
406 if(log.isDebugEnabled()) {
407 log.debug("object: {}", object);
408 log.debug("list: {}", list);
412 log.warn("format error: ex) object in list");
415 // direction:"row|col" 繰返し方向 デフォルト row
416 else if(mtForeach.group(i).startsWith(TLP_DIRECTION)) {
417 direction = mtForeach.group(i).replaceAll(TLP_DIRECTION + rgAttr, $1);
418 log.debug("{}: {}", TLP_DIRECTION, direction);
419 if(!ROW.equalsIgnoreCase(direction) && !COL.equalsIgnoreCase(direction)) {
420 log.warn("{} is illegal argument. set default: {}", TLP_DIRECTION, ROW);
424 // shift:"true|false" foreachレンジより後のセルに対するシフト指定 デフォルト false
425 else if(mtForeach.group(i).startsWith(TLP_SHIFT)) {
426 shift = BooleanUtils.toBoolean(mtForeach.group(i).replaceAll(TLP_SHIFT + rgAttr, $1).trim());
427 log.debug("{}: {}", TLP_SHIFT, shift);
429 // blick:"true|false" foreachレンジをブロック範囲で繰り返すかの指定 デフォルト true
430 else if(mtForeach.group(i).startsWith(TLP_BLOCK)) {
431 block = BooleanUtils.toBoolean(mtForeach.group(i).replaceAll(TLP_BLOCK + rgAttr, $1).trim());
432 log.debug("{}: {}", TLP_BLOCK, block);
434 // style:"copy|^copy" foreachレンジのセルスタイルのコピー指定 デフォルト copy
435 else if(mtForeach.group(i).startsWith(TLP_STYLE)) {
436 style = mtForeach.group(i).replaceAll(TLP_STYLE + rgAttr, $1).trim();
437 log.debug("{}: {}", TLP_STYLE, style);
439 // start:"numberExpression"
440 else if(mtForeach.group(i).startsWith(TLP_START)) {
441 start = mtForeach.group(i).replaceAll(TLP_START + rgAttr, $1);
442 log.debug("{}: {}", TLP_START, start);
444 // end:"numberExpression"
445 else if(mtForeach.group(i).startsWith(TLP_END)) {
446 end = mtForeach.group(i).replaceAll(TLP_END + rgAttr, $1);
447 log.debug("{}: {}", TLP_END, end);
449 // rows:"number" 範囲 デフォルト 1
450 else if(mtForeach.group(i).startsWith(TLP_ROWS)) {
451 rowSpan = NumberUtils.toInt(mtForeach.group(i).replaceAll(TLP_ROWS + rgAttr, $1).trim());
452 log.debug("{}: {}", TLP_ROWS, rowSpan);
454 log.warn("{} is illegal argument. set default: {}", TLP_ROWS, SPAN_DEF);
458 // cols:"number" 範囲 デフォルト 1
459 else if(mtForeach.group(i).startsWith(TLP_COLS)) {
460 colSpan = NumberUtils.toInt(mtForeach.group(i).replaceAll(TLP_COLS + rgAttr, $1).trim());
461 log.debug("{}: {}", TLP_COLS, colSpan);
463 log.warn("{} is illegal argument. set default: {}", TLP_COLS, SPAN_DEF);
470 else if((mtEl = ptEl.matcher(matchString)).find()) {
471 log.debug("type: {}", EL);
478 expression = mtEl.group(1).trim();
479 log.debug("expression: {}", expression);
483 log.warn("TL type: ???");
489 log.debug("unmatch");
492 log.trace("matchTL end: {}", findFlg);
499 private void evaluate() {
500 log.trace("evaluate start");
502 Object elResult; // パース結果保持用
503 String newCellVal; // セル値
506 elResult = elMgr.evaluate(expression);
507 if(elResult == null) {
508 log.debug("evaluate result is null");
511 log.debug("evaluate result: {}", elResult.toString());
513 // マッチ1件目をevaluate結果で置換
514 newCellVal = replaceFirst(elResult == null ? "" : elResult.toString());
515 log.debug("replace value: {}", newCellVal);
517 // newCellValが空白でないなら
518 if(!"".equals(newCellVal.trim())) {
521 if(NumberUtils.isNumber(newCellVal)) {
522 // もともと文字列セルなら数値セルに変更し値をセット
523 if(cell.getCellType() == Cell.CELL_TYPE_STRING) {
524 cell.setCellType(Cell.CELL_TYPE_BLANK);
525 cell.setCellType(Cell.CELL_TYPE_NUMERIC);
528 cell.setCellValue(Integer.parseInt(newCellVal));
529 log.debug("set value type: Integer");
532 catch(NumberFormatException e) {
533 cell.setCellValue(NumberUtils.toDouble(newCellVal));
534 log.debug("set value type: Double");
537 // もともと計算式セルの場合は計算式として値をセット
541 cell.setCellFormula(newCellVal);
542 log.debug("set value type: Formula");
545 catch(FormulaParseException e) {
546 log.warn("formula set error: {}", e.getMessage(), e);
547 cell.setCellType(Cell.CELL_TYPE_BLANK);
548 cell.setCellType(Cell.CELL_TYPE_NUMERIC);
551 cell.setCellValue(Integer.parseInt(newCellVal));
552 log.debug("set value type: Integer");
555 catch(NumberFormatException e2) {
556 cell.setCellValue(NumberUtils.toDouble(newCellVal));
557 log.debug("set value type: Double");
565 else if(StringUtils.equalsIgnoreCase(newCellVal, "true") || StringUtils.equalsIgnoreCase(newCellVal, "false")) {
566 // もともと文字列セルならBoolセルに変更し値をセット
567 if(cell.getCellType() == Cell.CELL_TYPE_STRING) {
568 cell.setCellType(Cell.CELL_TYPE_BLANK);
569 cell.setCellType(Cell.CELL_TYPE_BOOLEAN);
570 cell.setCellValue(BooleanUtils.toBoolean(newCellVal));
571 log.debug("set value type: Boolean");
573 // もともと計算式セルの場合は計算式として値をセット
577 cell.setCellFormula(newCellVal);
578 log.debug("set value type: Formula");
581 catch(FormulaParseException e) {
582 log.warn("formula set error: {}", e.getMessage(), e);
583 cell.setCellType(Cell.CELL_TYPE_BLANK);
584 cell.setCellType(Cell.CELL_TYPE_BOOLEAN);
585 cell.setCellValue(BooleanUtils.toBoolean(newCellVal));
586 log.debug("set value type: Boolean");
596 if(DateUtils.parseDateStrictly(newCellVal, DATE_FORMATS) != null) {
597 // もともと文字列セルなら数値セルに変更し値をセット
598 if(cell.getCellType() == Cell.CELL_TYPE_STRING) {
599 cell.setCellType(Cell.CELL_TYPE_BLANK);
600 cell.setCellType(Cell.CELL_TYPE_NUMERIC);
602 if(FORMAT_GENERAL == cell.getCellStyle().getDataFormat()) {
603 cell.setCellValue(newCellVal);
604 log.debug("set value type: String");
607 cell.setCellValue(DateUtils.parseDateStrictly(newCellVal, DATE_FORMATS));
608 log.debug("set value type: Date");
611 // もともと計算式セルの場合は計算式として値をセット
615 cell.setCellFormula(newCellVal);
616 log.debug("set value type: Formula");
619 catch(FormulaParseException e) {
620 log.warn("formula set error: {}", e.getMessage(), e);
621 cell.setCellType(Cell.CELL_TYPE_BLANK);
622 cell.setCellType(Cell.CELL_TYPE_NUMERIC);
623 cell.setCellValue(DateUtils.parseDateStrictly(newCellVal, DATE_FORMATS));
624 log.debug("set value type: Date");
632 throw new ParseException("", 0);
635 catch(ParseException e) {
637 if(cell.getCellType() == Cell.CELL_TYPE_STRING) {
638 cell.setCellValue(newCellVal);
639 log.debug("set value type: String");
643 cell.setCellFormula(newCellVal);
644 log.debug("set value type: Formula");
646 catch(FormulaParseException e2) {
647 log.warn("formula set error: {}", e2.getMessage(), e2);
648 cell.setCellType(Cell.CELL_TYPE_BLANK);
649 cell.setCellType(Cell.CELL_TYPE_STRING);
650 cell.setCellValue(newCellVal);
651 log.debug("set value type: String");
661 cell.setCellType(Cell.CELL_TYPE_BLANK);
666 log.trace("evaluate end");
672 private void parseForeach() {
673 log.trace("parseForeach start");
676 Cell fromCell, toCell;
679 Object[] mapKeys = null;
681 ArrayList<CellRangeAddress> rangeList = new ArrayList<>();
682 CellRangeAddress fromRange, toRange, tmpBfRange, tmpAfRange;
685 listObject = elMgr.evaluate(list);
686 if(listObject == null) {
687 log.debug("list is null eval response.");
688 log.trace("parseForeach end");
691 log.debug("list class: {}", listObject.getClass().getName());
693 // listObject Mapならキー取得
694 if(listObject instanceof Map) {
695 mapKeys = ((Map<?, ?>)listObject).keySet().toArray();
699 evalObject = elMgr.evaluate("size(" + list + ")");
700 // evalした結果がintでなければリスト不可なオブジェクトと判断
701 if(evalObject == null) {
702 log.error("list size unknown");
703 log.trace("parseForeach end");
706 else if(!(evalObject instanceof Integer)) {
707 log.error("list size is not Integer instance");
708 log.trace("parseForeach end");
711 listSize = (int) evalObject;
712 log.debug("list size: {}", listSize);
717 log.debug("start: {}", start);
718 // size(list) 等 式の可能性もあるのでevalする
719 evalObject = elMgr.evaluate(start);
720 if(evalObject != null) {
721 // evalした結果がintでなければデフォルト
722 if(!(evalObject instanceof Integer)) {
723 log.warn("start is not Integer instance. start set default: {}", IDX_BASE);
727 startIdx = (int) evalObject;
730 // startIdxが0の場合、1に補正
733 else if(startIdx < 0) {
734 // startIdxがマイナス値の場合、listのサイズからの逆順とする
736 startIdx = listSize + startIdx + IDX_BASE;
738 else if(startIdx > listSize) {
739 // startIdxがリストのサイズより大きい場合、リストのサイズに切り詰める
744 // evalした結果がnullの場合はデフォルト
746 log.debug("start is null eval response. start set default: {}", IDX_BASE);
751 log.debug("start is null. start set default: {}", IDX_BASE);
754 log.debug("startIdx: {}", startIdx);
759 log.debug("end: {}", end);
760 // size(list) 等 式の可能性もあるのでevalする
761 evalObject = elMgr.evaluate(end);
762 if(evalObject != null) {
763 // evalした結果がintでなければリストサイズ
764 if(!(evalObject instanceof Integer)) {
765 log.warn("end is not Integer instance. end set list size: {}", listSize);
769 endIdx = (int) evalObject;
772 // endIdxが0の場合、リストサイズ
775 else if(endIdx < 0) {
776 // endIdxがマイナス値の場合、listのサイズからの逆順とする
778 endIdx = listSize + endIdx + IDX_BASE;
780 else if(endIdx > listSize) {
781 // endIdxがリストのサイズより大きい場合、リストのサイズに切り詰める
786 // evalした結果がnullの場合はリストサイズ
788 log.debug("end is null eval response. end set list size: {}", listSize);
793 log.debug("end is null. end set list size: {}", listSize);
797 if(log.isDebugEnabled()) {
798 log.debug("endIdx: {}", endIdx);
799 log.debug("direction: {}", direction);
800 log.debug("shift: {}", shift);
801 log.debug("block: {}", block);
802 log.debug("style: {}", style);
805 // コピー元範囲 block:falseの場合、行・列全体に範囲を広げる
807 // 繰返し方向横(列)(行がデフォルト)
808 if(COL.equalsIgnoreCase(direction)) {
809 fromRange = new CellRangeAddress(sheet.getFirstRowNum(), sheet.getLastRowNum(), startColIdx, startColIdx + colSpan - 1);
813 fromRange = new CellRangeAddress(startRowIdx, startRowIdx + rowSpan - 1, 0, ExcelUtil.getLastColNum(sheet));
817 fromRange = new CellRangeAddress(startRowIdx, startRowIdx + rowSpan - 1, startColIdx, startColIdx + colSpan - 1);
820 fromRange = ExcelUtil.getIntersectRange(sheet, fromRange);
822 // 繰返しコピー回数1以上なら、コピー先範囲シフト・クリア等実施
823 if(startIdx != endIdx) {
825 int copyCount = startIdx < endIdx ? endIdx - startIdx : startIdx - endIdx;
826 // 繰返し方向横(列)(行がデフォルト)
827 if(COL.equalsIgnoreCase(direction)) {
828 toRange = new CellRangeAddress(
829 fromRange.getFirstRow(),
830 fromRange.getLastRow(),
831 fromRange.getLastColumn() + 1,
832 fromRange.getLastColumn() + (fromRange.getLastColumn() - fromRange.getFirstColumn() + 1) * copyCount);
836 toRange = new CellRangeAddress(
837 fromRange.getLastRow() + 1,
838 fromRange.getLastRow() + (fromRange.getLastRow() - fromRange.getFirstRow() + 1) * copyCount,
839 fromRange.getFirstColumn(),
840 fromRange.getLastColumn());
843 // shift:trueの場合、コピー先範囲の後続範囲をシフト
846 int distance = (startIdx > endIdx ? startIdx - endIdx : endIdx - startIdx);
848 // 繰返し方向横(列)(行がデフォルト)
849 if(COL.equalsIgnoreCase(direction)) {
852 ExcelUtil.shift(sheet, new CellRangeAddress(fromRange.getFirstRow(), fromRange.getLastRow(), fromRange.getLastColumn() + 1, fromRange.getLastColumn() + 1), COL, distance, block);
858 ExcelUtil.shift(sheet, new CellRangeAddress(fromRange.getLastRow() + 1, fromRange.getLastRow() + 1, fromRange.getFirstColumn(), fromRange.getLastColumn()), ROW, distance, block);
861 // shift:falseの場合、コピー先範囲をクリア
863 ExcelUtil.clearRange(sheet, toRange, COPY.equalsIgnoreCase(style), COPY.equalsIgnoreCase(style));
865 // style:copyの場合、コピー元範囲の結合保持・解除
866 if(COPY.equalsIgnoreCase(style)) {
867 // コピー元範囲の結合状態チェック・保持。コピー先範囲の結合解除
868 CellRangeAddress tmpRange;
869 for(int i = 0; i < sheet.getNumMergedRegions(); i++) {
870 tmpRange = sheet.getMergedRegion(i);
872 switch(CellRangeUtil.intersect(fromRange, tmpRange)) {
873 case CellRangeUtil.INSIDE:
874 rangeList.add(tmpRange);
875 log.debug("from range inside mergedRegion. save: {}", tmpRange.formatAsString());
877 case CellRangeUtil.ENCLOSES:
878 log.warn("from range encloses mergedRegion. remove: {}", tmpRange.formatAsString());
879 sheet.removeMergedRegion(i);
881 case CellRangeUtil.OVERLAP:
882 log.warn("from range overlap mergedRegion. remove: {}", tmpRange.formatAsString());
883 sheet.removeMergedRegion(i);
891 boolean copyFlg = true;
892 for(int i = startIdx, cpCount = 0; (startIdx <= endIdx && i <= endIdx || startIdx > endIdx && i >= endIdx); i = (startIdx <= endIdx ? i + 1 : i - 1), cpCount++) {
894 for(int r = fromRange.getFirstRow(); r <= fromRange.getLastRow(); r++) {
895 // 繰返し方向縦(行)の場合、コピー先の範囲チェック
896 if(ROW.equalsIgnoreCase(direction) && (r + rowSpan * cpCount < 0 || r + rowSpan * cpCount > ExcelUtil.getMaxRowIndex(sheet))) {
898 log.warn("to row outside sheet");
905 fromRow = sheet.getRow(r);
907 toRow = ROW.equalsIgnoreCase(direction) ? sheet.getRow(r + rowSpan * cpCount) : fromRow;
909 // コピー元行がnullならコピー先行もnull。continue
910 if(fromRow == null) {
912 log.debug("continue. from row [{}] is null. to row [{}] remove", (r + 1), (toRow.getRowNum() + 1));
913 sheet.removeRow(toRow);
916 log.debug("continue. from row [{}] and to row [{}] is null", (r + 1), ((ROW.equalsIgnoreCase(direction) ? (r + rowSpan * cpCount) : r) + 1));
922 if(toRow == null) toRow = sheet.createRow(r + rowSpan * cpCount);
924 // コピー元行・コピー先行 行番号が異なり、block falseなら行情報(高さ)もコピー
925 if(fromRow.getRowNum() != toRow.getRowNum() && !block) toRow.setHeight(fromRow.getHeight());
928 for(int c = fromRange.getFirstColumn(); c <= fromRange.getLastColumn(); c++) {
929 // 繰返し方向横(列)の場合、コピー先の範囲チェック
930 if(COL.equalsIgnoreCase(direction) && (c + colSpan * cpCount < 0 || c + colSpan * cpCount > ExcelUtil.getMaxColumnIndex(sheet))) {
932 log.warn("to cell outside sheet");
937 fromCell = fromRow.getCell(c);
939 toCell = toRow.getCell(COL.equalsIgnoreCase(direction) ? c + colSpan * cpCount : c);
941 // コピー元セルがnullならコピー先セルもnull
942 if(fromCell == null) {
944 log.debug("continue. from cell [{}] is null. to cell [{}] remove", (new CellReference(fromRow.getRowNum(), c)).formatAsString(), (new CellReference(toCell.getRowIndex(), toCell.getColumnIndex())).formatAsString());
945 toRow.removeCell(toCell);
948 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());
954 if(toCell == null) toCell = toRow.createCell(COL.equalsIgnoreCase(direction) ? c + colSpan * cpCount : c);
956 // コピー元列・コピー先列 列番号が異なり、block falseなら列情報(幅)もコピー ( 繰返しループ1回目のみ)
957 if(cpCount == 0 && fromCell.getColumnIndex() != toCell.getColumnIndex() && !block)
958 sheet.setColumnWidth(toCell.getColumnIndex(), sheet.getColumnWidth(fromCell.getColumnIndex()));
961 if(cpCount > 0 && COPY.equalsIgnoreCase(style)) {
963 toCell.setCellStyle(fromCell.getCellStyle());
966 switch(fromCell.getCellType()) {
967 case Cell.CELL_TYPE_BLANK:
968 toCell.setCellType(Cell.CELL_TYPE_BLANK);
970 case Cell.CELL_TYPE_BOOLEAN:
971 toCell.setCellType(Cell.CELL_TYPE_BOOLEAN);
972 toCell.setCellValue(fromCell.getBooleanCellValue());
974 case Cell.CELL_TYPE_ERROR:
975 toCell.setCellType(Cell.CELL_TYPE_ERROR);
976 toCell.setCellErrorValue(fromCell.getErrorCellValue());
978 case Cell.CELL_TYPE_FORMULA:
979 toCell.setCellType(Cell.CELL_TYPE_FORMULA);
981 toCell.setCellFormula(
982 ExcelUtil.getMoveFormula(
984 fromCell.getCellFormula().replace(
985 (cpCount == 0 ? object : list + "[" + (mapKeys == null ? (startIdx - 1) : "'" + mapKeys[startIdx - 1] + "'") + "]"), list + "[" + (mapKeys == null ? (i - 1) : "'" + mapKeys[i - 1] + "'") + "]"),
986 toCell.getRowIndex() - fromCell.getRowIndex(),
987 toCell.getColumnIndex() - fromCell.getColumnIndex()
990 log.debug("to cell Formula: {}", toCell.getCellFormula());
992 case Cell.CELL_TYPE_NUMERIC:
993 toCell.setCellType(Cell.CELL_TYPE_NUMERIC);
994 toCell.setCellValue(fromCell.getNumericCellValue());
996 case Cell.CELL_TYPE_STRING:
997 toCell.setCellType(Cell.CELL_TYPE_STRING);
998 toCell.setCellValue(fromCell.getStringCellValue().replace((cpCount == 0 ? object : list + "[" + (mapKeys == null ? (startIdx - 1) : "'" + mapKeys[startIdx - 1] + "'") + "]"), list + "[" + (mapKeys == null ? (i - 1) : "'" + mapKeys[i - 1] + "'") + "]"));
999 log.debug("to cell string: {}", toCell.getStringCellValue());
1004 // 繰返しコピーフラグfalseならbreak
1009 // for(int r = fromRange.getFirstRow(); r <= fromRange.getLastRow(); r++) {
1010 // row = sheet.getRow(r);
1011 // // コピー元行がnullで繰返し方向横(列)の場合
1012 // if(row == null && COL.equalsIgnoreCase(direction)) {
1013 // // コピー先行もnullとなるのでセルの処理はせず終了
1014 // log.debug("continue. direction: col from row [{}] is null", (r + 1));
1019 // for(int c = fromRange.getFirstColumn(); c <= fromRange.getLastColumn(); c++) {
1020 // // コピー元行がnullの場合セルもnull
1021 // if(row == null) {
1024 // cell = row.getCell(c);
1028 // for(int i = startIdx, cpCount = 0; (startIdx <= endIdx && i <= endIdx || startIdx > endIdx && i >= endIdx); i = (startIdx <= endIdx ? i + 1 : i - 1), cpCount++) {
1029 // // 繰返し方向横(列)(行がデフォルト)
1030 // if(COL.equalsIgnoreCase(direction)) {
1032 // if(c + colSpan * cpCount < 0 || c + colSpan * cpCount > ExcelUtil.getMaxColumnIndex(sheet)) {
1033 // log.warn("to cell outside sheet");
1037 // toCell = row.getCell(c + colSpan * cpCount);
1038 // // コピー元セルがnullならコピー先セルもnull
1039 // if(cell == null) {
1040 // if(toCell != null) {
1041 // toRow.removeCell(toCell);
1042 // log.debug("continue. from cell [{}] is null. to cell [{}] remove", (new CellReference(r, c)).formatAsString(), (new CellReference(r, c + colSpan * cpCount)).formatAsString());
1045 // log.debug("continue. from cell [{}] and to cell [{}] is null", (new CellReference(r, c)).formatAsString(), (new CellReference(r, c + colSpan * cpCount)).formatAsString());
1050 // if(toCell == null) toCell = row.createCell(c + colSpan * cpCount);
1051 // // block falseなら列情報(幅)もコピー
1053 // sheet.setColumnWidth(toCell.getColumnIndex(), sheet.getColumnWidth(cell.getColumnIndex()));
1060 // if(r + rowSpan * cpCount < 0 || r + rowSpan * cpCount > ExcelUtil.getMaxRowIndex(sheet)) {
1061 // log.warn("to row outside sheet");
1065 // toRow = sheet.getRow(r + rowSpan * cpCount);
1067 // // コピー元行がnullならコピー先行もnull
1068 // if(row == null) {
1069 // if(toRow != null) {
1070 // sheet.removeRow(toRow);
1071 // log.debug("continue. from row [{}] is null. to row [{}] remove", (r + 1));
1074 // log.debug("continue. from and to row is null");
1079 // if(toRow == null) toRow = sheet.createRow(r + rowSpan * cpCount);
1080 // // block falseなら行情報(高さ)もコピー
1082 // toRow.setHeight(row.getHeight());
1084 // toCell = toRow.getCell(c);
1085 // // コピー元セルがnullならコピー先セルもnull
1086 // if(cell == null) {
1087 // if(toCell != null) {
1088 // toRow.removeCell(toCell);
1089 // log.debug("continue. from cell is null. to cell remove");
1092 // log.debug("continue. from cell [{}] and to cell [{}] is null", (new CellReference(r, c)).formatAsString(), (new CellReference(r + rowSpan * cpCount, c)).formatAsString());
1097 // if(toCell == null) toCell = toRow.createCell(c);
1103 // if(cpCount > 0 && COPY.equalsIgnoreCase(style)) {
1105 // toCell.setCellStyle(cell.getCellStyle());
1108 // switch(cell.getCellType()) {
1109 // case Cell.CELL_TYPE_BLANK:
1110 // toCell.setCellType(Cell.CELL_TYPE_BLANK);
1112 // case Cell.CELL_TYPE_BOOLEAN:
1113 // toCell.setCellType(Cell.CELL_TYPE_BOOLEAN);
1114 // toCell.setCellValue(cell.getBooleanCellValue());
1116 // case Cell.CELL_TYPE_ERROR:
1117 // toCell.setCellType(Cell.CELL_TYPE_ERROR);
1118 // toCell.setCellErrorValue(cell.getErrorCellValue());
1120 // case Cell.CELL_TYPE_FORMULA:
1121 // toCell.setCellType(Cell.CELL_TYPE_FORMULA);
1122 // // 数式のパース・移動先に合わせる
1123 // toCell.setCellFormula(
1124 // ExcelUtil.getMoveFormula(
1126 // cell.getCellFormula().replace(
1127 // (i == startIdx ? object : list + "[" + (mapKeys == null ? (startIdx - 1) : "'" + mapKeys[startIdx - 1] + "'") + "]"), list + "[" + (mapKeys == null ? (i - 1) : "'" + mapKeys[i - 1] + "'") + "]"),
1128 // toCell.getRowIndex() - cell.getRowIndex(),
1129 // toCell.getColumnIndex() - cell.getColumnIndex()
1132 // log.debug("to cell Formula: {}", toCell.getCellFormula());
1134 // case Cell.CELL_TYPE_NUMERIC:
1135 // toCell.setCellType(Cell.CELL_TYPE_NUMERIC);
1136 // toCell.setCellValue(cell.getNumericCellValue());
1138 // case Cell.CELL_TYPE_STRING:
1139 // toCell.setCellType(Cell.CELL_TYPE_STRING);
1140 // toCell.setCellValue(cell.getStringCellValue().replace((i == startIdx ? object : list + "[" + (mapKeys == null ? (startIdx - 1) : "'" + mapKeys[startIdx - 1] + "'") + "]"), list + "[" + (mapKeys == null ? (i - 1) : "'" + mapKeys[i - 1] + "'") + "]"));
1141 // log.debug("to cell string: {}", toCell.getStringCellValue());
1148 if(COPY.equalsIgnoreCase(style)) {
1152 if(COL.equalsIgnoreCase(direction)) {
1160 if(!rangeList.isEmpty()) {
1163 for(int c = 0; c < rangeList.size(); c++) {
1164 tmpBfRange = rangeList.get(c);
1166 for(int i = startIdx, cpCount = 0; (startIdx <= endIdx && i <= endIdx || startIdx > endIdx && i >= endIdx); i = (startIdx <= endIdx ? i + 1 : i - 1), cpCount++) {
1167 // 初回はコピーしない(コピー元だから)
1168 if(i == startIdx) continue;
1170 tmpAfRange = new CellRangeAddress(
1171 tmpBfRange.getFirstRow() + (addRow * cpCount),
1172 tmpBfRange.getLastRow() + (addRow * cpCount),
1173 tmpBfRange.getFirstColumn() + (addCol * cpCount),
1174 tmpBfRange.getLastColumn() + (addCol * cpCount));
1175 if(ExcelUtil.validateRange(sheet, tmpAfRange)) {
1176 sheet.addMergedRegion(tmpAfRange);
1177 log.debug("mergedRegion copy. from: [{}] to: [{}]", tmpBfRange.formatAsString(), tmpAfRange.formatAsString());
1185 if(sheet instanceof HSSFSheet) {
1186 CellRangeAddress cpRange;
1188 HSSFPatriarch patriarch = ((HSSFSheet)sheet).getDrawingPatriarch();
1189 if(patriarch != null) {
1190 List<HSSFShape> shapes = ((HSSFSheet)sheet).getDrawingPatriarch().getChildren();
1191 if(shapes != null) {
1192 HSSFClientAnchor fAnchor, tAnchor;
1196 for (int i = 0; i < shapes.size(); i++) {
1197 fAnchor = (HSSFClientAnchor)shapes.get(i).getAnchor();
1198 if(fAnchor != null) {
1199 r1 = fAnchor.getRow1();
1200 c1 = fAnchor.getCol1();
1201 r2 = fAnchor.getRow2();
1202 c2 = fAnchor.getCol2();
1203 tmpRange = new CellRangeAddress(r1, r2, c1, c2);
1204 switch(CellRangeUtil.intersect(fRange, tmpRange)) {
1205 case CellRangeUtil.INSIDE:
1206 case CellRangeUtil.OVERLAP:
1208 if(!ROW.equalsIgnoreCase(direction)) {
1209 tAnchor = new HSSFClientAnchor(
1210 fAnchor.getDx1(), fAnchor.getDy1(),
1211 fAnchor.getDx2(), fAnchor.getDy2(),
1212 (short) (c1 + (colSpan * cpCount)), r1,
1213 (short) (c2 + (colSpan * cpCount)), r2);
1214 cpRange = new CellRangeAddress(r1, r2, c1 + (colSpan * cpCount), c2 + (colSpan * cpCount));
1218 tAnchor = new HSSFClientAnchor(
1219 fAnchor.getDx1(), fAnchor.getDy1(),
1220 fAnchor.getDx2(), fAnchor.getDy2(),
1221 c1, r1 + (rowSpan * cpCount),
1222 c2, r2 + (rowSpan * cpCount));
1223 cpRange = new CellRangeAddress(r1 + (rowSpan * cpCount), r2 + (rowSpan * cpCount), c1, c2);
1225 if(log.isDebugEnabled()) log.debug("object copy from: " + tmpRange.formatAsString() + " to: " + cpRange.formatAsString());
1227 patriarch.addShape(new shapes.get(i),)
1235 // オブジェクトのコピー Excel2007以降 ooxml形式のみ対応
1236 if(sheet instanceof XSSFSheet) {
1238 CTDrawing ctDrawing;
1239 CTTwoCellAnchor fAnchor, cpAnchor;
1243 for(POIXMLDocumentPart part : ((XSSFSheet)sheet).getRelations()) {
1244 if(part == null) continue;
1245 log.debug("DocumentPart class: {}", part.getClass().getName());
1246 // DocumentPartがDrawingオブジェクトの場合
1247 if(part instanceof XSSFDrawing) {
1248 ctDrawing = ((XSSFDrawing) part).getCTDrawing();
1249 if(ctDrawing != null) {
1251 int alSize = ctDrawing.getTwoCellAnchorList().size();
1252 for (int i = 0; i < alSize; i++) {
1253 fAnchor = ctDrawing.getTwoCellAnchorList().get(i);
1254 // GraphicFrameをもつグラフ、スマートアートは簡単にはコピーできないので非対応
1255 if(fAnchor.isSetGraphicFrame()) continue;
1258 from = fAnchor.getFrom();
1261 to = fAnchor.getTo();
1264 tmpBfRange = new CellRangeAddress(r1, r2, c1, c2);
1266 // コピー元レンジに含まれている、掛かっているならコピー
1267 switch(CellRangeUtil.intersect(fromRange, tmpBfRange)) {
1268 case CellRangeUtil.INSIDE:
1269 case CellRangeUtil.OVERLAP:
1271 for(int j = startIdx, cpCount = 0; (startIdx <= endIdx && j <= endIdx || startIdx > endIdx && j >= endIdx); j = (startIdx <= endIdx ? j + 1 : j - 1), cpCount++) {
1272 // 初回はコピーしない(コピー元だから)
1273 if(j == startIdx) continue;
1274 // TODO これでオブジェクト(アンカー)のコピーができる!!
1275 cpAnchor = ctDrawing.addNewTwoCellAnchor();
1276 cpAnchor.set(fAnchor.copy());
1277 from = cpAnchor.getFrom();
1278 from.setRow(from.getRow() + (addRow * cpCount));
1279 from.setCol(from.getCol() + (addCol * cpCount));
1280 to = cpAnchor.getTo();
1281 to.setRow(to.getRow() + (addRow * cpCount));
1282 to.setCol(to.getCol() + (addCol * cpCount));
1283 if(log.isDebugEnabled()) {
1284 tmpAfRange = new CellRangeAddress(from.getRow(), to.getRow(), from.getCol(), to.getCol());
1285 log.debug("object copy from: [{}] to: [{}]", tmpBfRange.formatAsString(), tmpAfRange.formatAsString());
1294 catch(Exception e) {
1295 log.error("object copy error: " + e.getMessage(), e);
1299 log.trace("parseForeach end");
1305 private void parseIf() {
1306 log.trace("parseIf start");
1310 Object elResult = elMgr.evaluate(expression);
1311 if(elResult == null) {
1312 log.debug("evaluate result is null");
1315 else if(elResult instanceof Boolean) {
1316 result = (boolean) elResult;
1321 log.debug("evaluate result: {}", result);
1325 if(delete == null) {
1326 log.debug("{} is null set default: {}", TLP_DELETE, LEFT);
1329 else if(!LEFT.equalsIgnoreCase(delete) && !UP.equalsIgnoreCase(delete) && !CLEAR.equalsIgnoreCase(delete)) {
1330 log.warn("{} is illegal argument. set default: {}", TLP_DELETE, LEFT);
1334 log.debug("delete: {}", delete);
1335 delete = delete.toLowerCase().trim();
1341 // ExcelUtil.clearRange(sheet, (new CellRangeAddress(startRowIdx, startRowIdx + rowSpan - 1, startColIdx, startColIdx + colSpan - 1)), true, true);
1342 ExcelUtil.clearRange(sheet, (new CellRangeAddress(startRowIdx, startRowIdx + rowSpan - 1, startColIdx, startColIdx + colSpan - 1)), false, false);
1347 ExcelUtil.shift(sheet, new CellRangeAddress(startRowIdx, startRowIdx + rowSpan - 1, startColIdx + colSpan, startColIdx + colSpan), COL, -colSpan, block);
1352 ExcelUtil.shift(sheet, new CellRangeAddress(startRowIdx + rowSpan, startRowIdx + rowSpan, startColIdx, startColIdx + colSpan - 1), ROW, -rowSpan, block);
1355 log.trace("parseIf end");
1359 * マッチした結果がEL式であるかを返却
1361 * @return マッチした結果がEL式であればtrue。以外の場合false
1363 private boolean isEL() {
1364 return EL.equalsIgnoreCase(type);
1368 * マッチした結果がIf句であるかを返却
1370 * @return マッチした結果がIf句であればtrue。以外の場合false
1372 private boolean isIf() {
1373 return TL_IF.equalsIgnoreCase(type);
1377 * マッチした結果がForeach句であるかを返却
1379 * @return マッチした結果がForeach句であればtrue。以外の場合false
1381 private boolean isForeach() {
1382 return TL_FOREACH.equalsIgnoreCase(type);
1386 * 指示子全体検索結果から1つ目の指示子を置換
1388 * @param replacement 置換文字列
1392 private String replaceFirst(String replacement) {
1393 return mtAll.replaceFirst(replacement == null ? "" : replacement);
1399 * @return 再パース必要であればはtrue。不要であればfalse
1401 public boolean isReParseCell() {