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, "ture") || 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");
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);
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), true);
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);
892 for(int r = fromRange.getFirstRow(); r <= fromRange.getLastRow(); r++) {
893 row = sheet.getRow(r);
894 // コピー元行がnullで繰返し方向横(列)の場合
895 if(row == null && COL.equalsIgnoreCase(direction)) {
896 // コピー先行もnullとなるのでセルの処理はせず終了
897 log.debug("continue. direction: col from row [{}] is null", (r + 1));
902 for(int c = fromRange.getFirstColumn(); c <= fromRange.getLastColumn(); c++) {
903 // コピー元行がnullの場合セルもnull
907 cell = row.getCell(c);
911 for(int i = startIdx, cpCount = 0; (startIdx <= endIdx && i <= endIdx || startIdx > endIdx && i >= endIdx); i = (startIdx <= endIdx ? i + 1 : i - 1), cpCount++) {
912 // 繰返し方向横(列)(行がデフォルト)
913 if(COL.equalsIgnoreCase(direction)) {
915 if(c + colSpan * cpCount < 0 || c + colSpan * cpCount > ExcelUtil.getMaxColumnIndex(sheet)) {
916 log.warn("to cell outside sheet");
920 toCell = row.getCell(c + colSpan * cpCount);
921 // コピー元セルがnullならコピー先セルもnull
924 toRow.removeCell(toCell);
925 log.debug("continue. from cell [{}] is null. to cell [{}] remove", (new CellReference(r, c)).formatAsString(), (new CellReference(r, c + colSpan * cpCount)).formatAsString());
928 log.debug("continue. from cell [{}] and to cell [{}] is null", (new CellReference(r, c)).formatAsString(), (new CellReference(r, c + colSpan * cpCount)).formatAsString());
933 if(toCell == null) toCell = row.createCell(c + colSpan * cpCount);
934 // block falseなら列情報(幅)もコピー
936 sheet.setColumnWidth(toCell.getColumnIndex(), sheet.getColumnWidth(cell.getColumnIndex()));
943 if(r + rowSpan * cpCount < 0 || r + rowSpan * cpCount > ExcelUtil.getMaxRowIndex(sheet)) {
944 log.warn("to row outside sheet");
948 toRow = sheet.getRow(r + rowSpan * cpCount);
950 // コピー元行がnullならコピー先行もnull
953 sheet.removeRow(toRow);
954 log.debug("continue. from row [{}] is null. to row [{}] remove", (r + 1));
957 log.debug("continue. from and to row is null");
962 if(toRow == null) toRow = sheet.createRow(r + rowSpan * cpCount);
963 // block falseなら行情報(高さ)もコピー
965 toRow.setHeight(row.getHeight());
967 toCell = toRow.getCell(c);
968 // コピー元セルがnullならコピー先セルもnull
971 toRow.removeCell(toCell);
972 log.debug("continue. from cell is null. to cell remove");
975 log.debug("continue. from cell [{}] and to cell [{}] is null", (new CellReference(r, c)).formatAsString(), (new CellReference(r + rowSpan * cpCount, c)).formatAsString());
980 if(toCell == null) toCell = toRow.createCell(c);
986 if(cpCount > 0 && COPY.equalsIgnoreCase(style)) {
988 toCell.setCellStyle(cell.getCellStyle());
991 switch(cell.getCellType()) {
992 case Cell.CELL_TYPE_BLANK:
993 toCell.setCellType(Cell.CELL_TYPE_BLANK);
995 case Cell.CELL_TYPE_BOOLEAN:
996 toCell.setCellType(Cell.CELL_TYPE_BOOLEAN);
997 toCell.setCellValue(cell.getBooleanCellValue());
999 case Cell.CELL_TYPE_ERROR:
1000 toCell.setCellType(Cell.CELL_TYPE_ERROR);
1001 toCell.setCellErrorValue(cell.getErrorCellValue());
1003 case Cell.CELL_TYPE_FORMULA:
1004 toCell.setCellType(Cell.CELL_TYPE_FORMULA);
1006 toCell.setCellFormula(
1007 ExcelUtil.getMoveFormula(
1009 cell.getCellFormula().replace(
1010 (i == startIdx ? object : list + "[" + (mapKeys == null ? (startIdx - 1) : "'" + mapKeys[startIdx - 1] + "'") + "]"), list + "[" + (mapKeys == null ? (i - 1) : "'" + mapKeys[i - 1] + "'") + "]"),
1011 toCell.getRowIndex() - cell.getRowIndex(),
1012 toCell.getColumnIndex() - cell.getColumnIndex()
1015 log.debug("to cell Formula: {}", toCell.getCellFormula());
1017 case Cell.CELL_TYPE_NUMERIC:
1018 toCell.setCellType(Cell.CELL_TYPE_NUMERIC);
1019 toCell.setCellValue(cell.getNumericCellValue());
1021 case Cell.CELL_TYPE_STRING:
1022 toCell.setCellType(Cell.CELL_TYPE_STRING);
1023 toCell.setCellValue(cell.getStringCellValue().replace((i == startIdx ? object : list + "[" + (mapKeys == null ? (startIdx - 1) : "'" + mapKeys[startIdx - 1] + "'") + "]"), list + "[" + (mapKeys == null ? (i - 1) : "'" + mapKeys[i - 1] + "'") + "]"));
1024 log.debug("to cell string: {}", toCell.getStringCellValue());
1031 if(COPY.equalsIgnoreCase(style)) {
1035 if(COL.equalsIgnoreCase(direction)) {
1043 if(!rangeList.isEmpty()) {
1046 for(int c = 0; c < rangeList.size(); c++) {
1047 tmpBfRange = rangeList.get(c);
1049 for(int i = startIdx, cpCount = 1; (startIdx <= endIdx && i <= endIdx || startIdx > endIdx && i >= endIdx); i = (startIdx <= endIdx ? i + 1 : i - 1), cpCount++) {
1050 // 初回はコピーしない(コピー元だから)
1051 if(i == startIdx) continue;
1053 tmpAfRange = new CellRangeAddress(
1054 tmpBfRange.getFirstRow() + (addRow * cpCount),
1055 tmpBfRange.getLastRow() + (addRow * cpCount),
1056 tmpBfRange.getFirstColumn() + (addCol * cpCount),
1057 tmpBfRange.getLastColumn() + (addCol * cpCount));
1058 sheet.addMergedRegion(tmpAfRange);
1059 log.debug("mergedRegion copy. from: [{}] to: [{}]", tmpBfRange.formatAsString(), tmpAfRange.formatAsString());
1066 if(sheet instanceof HSSFSheet) {
1067 CellRangeAddress cpRange;
1069 HSSFPatriarch patriarch = ((HSSFSheet)sheet).getDrawingPatriarch();
1070 if(patriarch != null) {
1071 List<HSSFShape> shapes = ((HSSFSheet)sheet).getDrawingPatriarch().getChildren();
1072 if(shapes != null) {
1073 HSSFClientAnchor fAnchor, tAnchor;
1077 for (int i = 0; i < shapes.size(); i++) {
1078 fAnchor = (HSSFClientAnchor)shapes.get(i).getAnchor();
1079 if(fAnchor != null) {
1080 r1 = fAnchor.getRow1();
1081 c1 = fAnchor.getCol1();
1082 r2 = fAnchor.getRow2();
1083 c2 = fAnchor.getCol2();
1084 tmpRange = new CellRangeAddress(r1, r2, c1, c2);
1085 switch(CellRangeUtil.intersect(fRange, tmpRange)) {
1086 case CellRangeUtil.INSIDE:
1087 case CellRangeUtil.OVERLAP:
1089 if(!ROW.equalsIgnoreCase(direction)) {
1090 tAnchor = new HSSFClientAnchor(
1091 fAnchor.getDx1(), fAnchor.getDy1(),
1092 fAnchor.getDx2(), fAnchor.getDy2(),
1093 (short) (c1 + (colSpan * cpCount)), r1,
1094 (short) (c2 + (colSpan * cpCount)), r2);
1095 cpRange = new CellRangeAddress(r1, r2, c1 + (colSpan * cpCount), c2 + (colSpan * cpCount));
1099 tAnchor = new HSSFClientAnchor(
1100 fAnchor.getDx1(), fAnchor.getDy1(),
1101 fAnchor.getDx2(), fAnchor.getDy2(),
1102 c1, r1 + (rowSpan * cpCount),
1103 c2, r2 + (rowSpan * cpCount));
1104 cpRange = new CellRangeAddress(r1 + (rowSpan * cpCount), r2 + (rowSpan * cpCount), c1, c2);
1106 if(log.isDebugEnabled()) log.debug("object copy from: " + tmpRange.formatAsString() + " to: " + cpRange.formatAsString());
1108 patriarch.addShape(new shapes.get(i),)
1116 // オブジェクトのコピー Excel2007以降 ooxml形式のみ対応
1117 if(sheet instanceof XSSFSheet) {
1119 CTDrawing ctDrawing;
1120 CTTwoCellAnchor fAnchor, cpAnchor;
1124 for(POIXMLDocumentPart dr : ((XSSFSheet)sheet).getRelations()) {
1125 if(dr == null) continue;
1126 log.debug("DocumentPart class: {}", dr.getClass().getName());
1127 // DocumentPartがDrawingオブジェクトの場合
1128 if(dr instanceof XSSFDrawing) {
1129 ctDrawing = ((XSSFDrawing) dr).getCTDrawing();
1130 if(ctDrawing != null) {
1132 int alSize = ctDrawing.getTwoCellAnchorList().size();
1133 for (int i = 0; i < alSize; i++) {
1134 fAnchor = ctDrawing.getTwoCellAnchorList().get(i);
1135 // GraphicFrameをもつグラフ、スマートアートは簡単にはコピーできないので非対応
1136 if(fAnchor.isSetGraphicFrame()) continue;
1139 from = fAnchor.getFrom();
1142 to = fAnchor.getTo();
1145 tmpBfRange = new CellRangeAddress(r1, r2, c1, c2);
1147 // コピー元レンジに含まれている、掛かっているならコピー
1148 switch(CellRangeUtil.intersect(fromRange, tmpBfRange)) {
1149 case CellRangeUtil.INSIDE:
1150 case CellRangeUtil.OVERLAP:
1153 for(int j = startIdx, cpCount = 1; (startIdx <= endIdx && j <= endIdx || startIdx > endIdx && j >= endIdx); j = (startIdx <= endIdx ? j + 1 : j - 1), cpCount++) {
1154 // 初回はコピーしない(コピー元だから)
1155 if(j == startIdx) continue;
1156 // TODO これでオブジェクト(アンカー)のコピーができる!!
1157 cpAnchor = ctDrawing.addNewTwoCellAnchor();
1158 cpAnchor.set(fAnchor.copy());
1159 from = cpAnchor.getFrom();
1160 from.setRow(from.getRow() + (addRow * cpCount));
1161 from.setCol(from.getCol() + (addCol * cpCount));
1162 to = cpAnchor.getTo();
1163 to.setRow(to.getRow() + (addRow * cpCount));
1164 to.setCol(to.getCol() + (addCol * cpCount));
1165 if(log.isDebugEnabled()) {
1166 tmpAfRange = new CellRangeAddress(from.getRow(), to.getRow(), from.getCol(), to.getCol());
1167 log.debug("object copy from: [{}] to: [{}]", tmpBfRange.formatAsString(), tmpAfRange.formatAsString());
1176 catch(Exception e) {
1177 log.error("object copy error: " + e.getMessage(), e);
1181 log.trace("parseForeach end");
1187 private void parseIf() {
1188 log.trace("parseIf start");
1192 Object elResult = elMgr.evaluate(expression);
1193 if(elResult == null) {
1194 log.debug("evaluate result is null");
1197 else if(elResult instanceof Boolean) {
1198 result = (boolean) elResult;
1203 log.debug("evaluate result: {}", result);
1207 if(delete == null) {
1208 log.debug("{} is null set default: {}", TLP_DELETE, LEFT);
1211 else if(!LEFT.equalsIgnoreCase(delete) && !UP.equalsIgnoreCase(delete) && !CLEAR.equalsIgnoreCase(delete)) {
1212 log.warn("{} is illegal argument. set default: {}", TLP_DELETE, LEFT);
1216 log.debug("delete: {}", delete);
1217 delete = delete.toLowerCase().trim();
1223 ExcelUtil.clearRange(sheet, (new CellRangeAddress(startRowIdx, startRowIdx + rowSpan - 1, startColIdx, startColIdx + colSpan - 1)), true, true);
1228 ExcelUtil.shift(sheet, new CellRangeAddress(startRowIdx, startRowIdx + rowSpan - 1, startColIdx + colSpan, startColIdx + colSpan), COL, -colSpan, block);
1233 ExcelUtil.shift(sheet, new CellRangeAddress(startRowIdx + rowSpan, startRowIdx + rowSpan, startColIdx, startColIdx + colSpan - 1), ROW, -rowSpan, block);
1236 log.trace("parseIf end");
1240 * マッチした結果がEL式であるかを返却
1242 * @return マッチした結果がEL式であればtrue。以外の場合false
1244 private boolean isEL() {
1245 return EL.equalsIgnoreCase(type);
1249 * マッチした結果がIf句であるかを返却
1251 * @return マッチした結果がIf句であればtrue。以外の場合false
1253 private boolean isIf() {
1254 return TL_IF.equalsIgnoreCase(type);
1258 * マッチした結果がForeach句であるかを返却
1260 * @return マッチした結果がForeach句であればtrue。以外の場合false
1262 private boolean isForeach() {
1263 return TL_FOREACH.equalsIgnoreCase(type);
1267 * 指示子全体検索結果から1つ目の指示子を置換
1269 * @param replacement 置換文字列
1273 private String replaceFirst(String replacement) {
1274 return mtAll.replaceFirst(replacement == null ? "" : replacement);
1280 * @return 再パース必要であればはtrue。不要であればfalse
1282 public boolean isReParseCell() {