OSDN Git Service

ff366910d2ce32cb6a9a677dba89984020c49e5d
[jaxcel/jaxcel.git] / Jaxcel / src / org / hanei / jaxcel / parser / ForeachParser.java
1 /**
2  * Copyright 2014 Hanei Management Co.,Ltd. 
3  * 
4  * This file is part of Jaxcel
5  * 
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.
10  *
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.
15  *
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/>.
18  */
19 package org.hanei.jaxcel.parser;
20
21 import java.util.ArrayList;
22 import java.util.Map;
23 import java.util.regex.Matcher;
24 import java.util.regex.Pattern;
25
26 import org.apache.commons.lang3.BooleanUtils;
27 import org.apache.commons.lang3.math.NumberUtils;
28 import org.apache.poi.POIXMLDocumentPart;
29 import org.apache.poi.hssf.record.cf.CellRangeUtil;
30 import org.apache.poi.ss.usermodel.Cell;
31 import org.apache.poi.ss.usermodel.Row;
32 import org.apache.poi.ss.usermodel.Sheet;
33 import org.apache.poi.ss.util.CellRangeAddress;
34 import org.apache.poi.ss.util.CellReference;
35 import org.apache.poi.xssf.usermodel.XSSFDrawing;
36 import org.apache.poi.xssf.usermodel.XSSFSheet;
37 import org.hanei.jaxcel.report.ELManager;
38 import org.hanei.jaxcel.report.JaxcelContext;
39 import org.hanei.jaxcel.util.ExcelUtil;
40 import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing;
41 import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
42 import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor;
43
44 /**
45  * foreach句のパーサー実装<br>
46  * 
47  * @since 1.01.00
48  * @author Noboru Saito
49  */
50 public class ForeachParser extends AbstractTLParser {
51
52         private static final String ROWS = "rows";
53         private static final String COLS = "cols";
54         private static final String DIRECTION = "direction";
55         private static final String STYLE = "style";
56         private static final String SHIFT = "shift";
57         private static final String BLOCK = "block";
58         private static final String START = "start";
59         private static final String END = "end";
60
61         private static final String IN_PHRASE = " in ";
62
63         private static final String ROW = "row";
64         private static final String COL = "col";
65         private static final String COPY = "copy";
66         private static final int IDX_BASE = 1;
67         private static final int SPAN_DEF = 1;
68         @Override
69         public void parse(JaxcelContext context) {
70                 log.trace("parse start");
71
72                 Sheet sheet = context.getCurrentSheet();
73                 Cell cell = context.getCurrentCell();
74                 ELManager elMgr = context.getElManager();
75                 Map<String, Object> attributeMap = context.getAttributeMap();
76                 String expression = null;
77                 String object = null;
78                 String list = null;
79                 String direction = ROW;
80                 boolean shift = false;
81                 boolean block = true;
82                 String style = COPY;
83                 String start = null;            // start
84                 String end = null;                      // end
85                 int startIdx;
86                 int endIdx;
87                 int rowSpan = SPAN_DEF;         // row
88                 int colSpan = SPAN_DEF;         // column
89
90                 Row fromRow, toRow;
91                 Cell fromCell, toCell;
92                 String fromCellValue;
93                 Pattern pattern = null;
94                 Matcher matcher = null;
95                 Object evalObject;
96                 Object listObject;
97                 Object[] mapKeys = null;
98                 int listSize;
99                 ArrayList<CellRangeAddress> rangeList = new ArrayList<>(); 
100                 CellRangeAddress fromRange, toRange, tmpBfRange, tmpAfRange;
101
102                 // セルタイプのチェック、指示子をクリア
103                 switch(cell.getCellType()) {
104                 case Cell.CELL_TYPE_STRING:
105                         cell.setCellValue(ExcelUtil.replaceFirstCellValue(cell, context.getTemplateString(), ""));
106                         break;
107                 default:
108                         // セルタイプが文字列でない場合パース終了
109                         log.error("cell type is not strng");
110                         log.trace("parse end");
111                         return;
112                 }
113
114                 // EL式
115                 if(attributeMap.containsKey(Constants.EXPRESSION)) {
116                         expression = (String) attributeMap.get(Constants.EXPRESSION);
117                         log.debug("expression: {}", expression);
118                         String[] tmp = expression.split(IN_PHRASE, 2);
119                         if(tmp != null) {
120                                 object = tmp[0].trim();
121                                 list = tmp[1].trim();
122                         }
123                         else {
124                                 log.error("format error: ex) object in list");
125                                 log.trace("parse end");
126                                 return;
127                         }
128                 }
129                 else {
130                         // EL式が存在しな場合は終了
131                         log.error("expression is null");
132                         log.trace("parse end");
133                         return;
134                 }
135                 // リスト
136                 listObject = elMgr.evaluate(list);
137                 if(listObject == null) {
138                         log.error("list is null eval response.");
139                         log.trace("parse end");
140                         return; 
141                 }
142                 log.debug("list class: {}", listObject.getClass().getName());
143
144                 // listObject Mapならキー取得
145                 if(listObject instanceof Map) {
146                         mapKeys = ((Map<?, ?>)listObject).keySet().toArray();
147                         log.debug("mapKeys: {}", mapKeys);
148                 }
149
150                 // listのサイズ取得
151                 evalObject = elMgr.evaluate("size(" + list + ")");
152                 // evalした結果がintでなければリスト不可なオブジェクトと判断
153                 if(evalObject == null) {
154                         log.error("list size unknown");
155                         log.trace("parse end");
156                         return; 
157                 }
158                 else if(!(evalObject instanceof Integer)) {
159                         log.error("list size is not Integer instance");
160                         log.trace("parse end");
161                         return; 
162                 }
163                 listSize = (int) evalObject;
164                 log.debug("list size: {}", listSize);
165
166                 
167                 // direction:"row|col"  繰返し方向 デフォルト row
168                 if(attributeMap.containsKey(DIRECTION)) {
169                         direction = (String) attributeMap.get(DIRECTION);
170                         if(!ROW.equalsIgnoreCase(direction) && !COL.equalsIgnoreCase(direction)) {
171                                 log.warn("{} is illegal argument. set default: {}", DIRECTION, ROW);
172                                 direction = ROW;
173                         }
174                 }
175                 // shift:"true|false"  foreachレンジより後のセルに対するシフト指定 デフォルト false
176                 if(attributeMap.containsKey(SHIFT)) {
177                         shift = BooleanUtils.toBoolean((String) attributeMap.get(SHIFT));
178                 }
179                 // blick:"true|false"  foreachレンジをブロック範囲で繰り返すかの指定 デフォルト true
180                 if(attributeMap.containsKey(BLOCK)) {
181                         block = BooleanUtils.toBoolean((String) attributeMap.get(BLOCK));
182                 }
183                 // style:"copy|^copy"  foreachレンジのセルスタイルのコピー指定 デフォルト copy
184                 if(attributeMap.containsKey(STYLE)) {
185                         style = (String) attributeMap.get(STYLE);
186                 }
187             // start:"numberExpression"
188                 if(attributeMap.containsKey(START)) {
189                         start = (String) attributeMap.get(START);
190                 }
191             // end:"numberExpression"
192                 if(attributeMap.containsKey(END)) {
193                         end = (String) attributeMap.get(END);
194                 }
195                 // rows:"number"  範囲 デフォルト 1
196                 if(attributeMap.containsKey(ROWS)) {
197                         rowSpan = NumberUtils.toInt((String) attributeMap.get(ROWS));
198                         if(rowSpan <= 0) {
199                                 log.warn("{} is illegal argument. set default: {}", ROWS, SPAN_DEF);
200                                 rowSpan = SPAN_DEF;
201                         }
202                 }
203                 // cols:"number"  範囲 デフォルト 1
204                 if(attributeMap.containsKey(COLS)) {
205                         colSpan = NumberUtils.toInt((String) attributeMap.get(COLS));
206                         if(colSpan <= 0) {
207                                 log.warn("{} is illegal argument. set default: {}", COLS, SPAN_DEF);
208                                 colSpan = SPAN_DEF;
209                         }
210                 }
211
212                 // start インデックス
213                 if(start != null) {
214                         // size(list) 等 式の可能性もあるのでevalする
215                         evalObject = elMgr.evaluate(start);
216                         if(evalObject != null) {
217                                 // evalした結果がintでなければデフォルト
218                                 if(!(evalObject instanceof Integer)) {
219                                         log.warn("start is not Integer instance. start set default: {}", IDX_BASE);
220                                         startIdx = IDX_BASE;
221                                 }
222                                 else {
223                                         startIdx = (int) evalObject;
224                                         // startIdxの補正
225                                         if(startIdx == 0) {
226                                                 // startIdxが0の場合、1に補正
227                                                 startIdx = IDX_BASE;
228                                         }
229                                         else if(startIdx < 0) {
230                                                 // startIdxがマイナス値の場合、listのサイズからの逆順とする
231                                                 // -1 の場合リストのサイズ
232                                                 startIdx = listSize + startIdx + IDX_BASE;
233                                         }
234                                         else if(startIdx > listSize) {
235                                                 // startIdxがリストのサイズより大きい場合、リストのサイズに切り詰める
236                                                 startIdx = listSize;
237                                         }
238                                 }
239                         }
240                         // evalした結果がnullの場合はデフォルト
241                         else {
242                                 log.warn("start is null eval response. start set default: {}", IDX_BASE);
243                                 startIdx = IDX_BASE;
244                         }
245                 }
246                 else {
247                         log.debug("start is null. start set default: {}", IDX_BASE);
248                         startIdx = IDX_BASE;
249                 }
250
251                 // end インデックス
252                 if(end  != null) {
253                         // size(list) 等 式の可能性もあるのでevalする
254                         evalObject = elMgr.evaluate(end);
255                         if(evalObject != null) {
256                                 // evalした結果がintでなければリストサイズ
257                                 if(!(evalObject instanceof Integer)) {
258                                         log.warn("end is not Integer instance. end set list size: {}", listSize);
259                                         endIdx = listSize;
260                                 }
261                                 else {
262                                         endIdx = (int) evalObject;
263                                         // endIdxの補正
264                                         if(endIdx == 0) {
265                                                 // endIdxが0の場合、リストサイズ
266                                                 endIdx = listSize;
267                                         }
268                                         else if(endIdx < 0) {
269                                                 // endIdxがマイナス値の場合、listのサイズからの逆順とする
270                                                 // -1 の場合リストのサイズ
271                                                 endIdx = listSize + endIdx + IDX_BASE;
272                                         }
273                                         else if(endIdx > listSize) {
274                                                 // endIdxがリストのサイズより大きい場合、リストのサイズに切り詰める
275                                                 endIdx = listSize;
276                                         }
277                                 }
278                         }
279                         // evalした結果がnullの場合はリストサイズ
280                         else {
281                                 log.warn("end is null eval response. end set list size: {}", listSize);
282                                 endIdx = listSize;
283                         }
284                 }
285                 else {
286                         log.debug("end is null. end set list size: {}", listSize);
287                         endIdx = listSize;
288                 }
289                 
290                 if(log.isDebugEnabled()) {
291                         log.debug("object: {}", object);
292                         log.debug("list: {}", list);
293                         log.debug("start: {}", startIdx);
294                         log.debug("end: {}", endIdx);
295                         log.debug("rows: {}", rowSpan);
296                         log.debug("cols: {}", colSpan);
297                         log.debug("direction: {}", direction);
298                         log.debug("shift: {}", shift);
299                         log.debug("block: {}", block);
300                         log.debug("style: {}", style);
301                 }
302                 
303                 // コピー元範囲 block:falseの場合、行・列全体に範囲を広げる
304                 if(!block) {
305                         // 繰返し方向横(列)(行がデフォルト)
306                         if(COL.equalsIgnoreCase(direction)) {
307                                 fromRange = new CellRangeAddress(sheet.getFirstRowNum(), sheet.getLastRowNum(), cell.getColumnIndex(), cell.getColumnIndex() + colSpan - 1);
308                         }
309                         // 繰返し方向縦(行)の場合
310                         else {
311                                 fromRange = new CellRangeAddress(cell.getRowIndex(), cell.getRowIndex() + rowSpan - 1, 0, ExcelUtil.getLastColNum(sheet));
312                         }
313                 }
314                 else {
315                         fromRange = new CellRangeAddress(cell.getRowIndex(), cell.getRowIndex() + rowSpan - 1, cell.getColumnIndex(), cell.getColumnIndex() + colSpan - 1);
316                 }
317                 // シートに収まる範囲にリサイズ
318                 fromRange = ExcelUtil.getIntersectRange(sheet, fromRange);
319
320                 // 繰返しコピー回数1以上なら、コピー先範囲シフト・クリア等実施
321                 if(startIdx != endIdx) {
322                         // コピー先範囲の範囲特定
323                         int copyCount = startIdx < endIdx ? endIdx - startIdx : startIdx - endIdx;
324                         // 繰返し方向横(列)(行がデフォルト)
325                         if(COL.equalsIgnoreCase(direction)) {
326                                 toRange = new CellRangeAddress(
327                                                 fromRange.getFirstRow(), 
328                                                 fromRange.getLastRow(), 
329                                                 fromRange.getLastColumn() + 1, 
330                                                 fromRange.getLastColumn() + (fromRange.getLastColumn() - fromRange.getFirstColumn() + 1) * copyCount);
331                         }
332                         // 繰返し方向縦(行)の場合
333                         else {
334                                 toRange = new CellRangeAddress(
335                                                 fromRange.getLastRow() + 1, 
336                                                 fromRange.getLastRow() + (fromRange.getLastRow() - fromRange.getFirstRow() + 1) * copyCount, 
337                                                 fromRange.getFirstColumn(), 
338                                                 fromRange.getLastColumn());
339                         }
340
341                         // shift:trueの場合、コピー先範囲の後続範囲をシフト
342                         if(shift) {
343                                 // 移動量
344                                 int distance = (startIdx > endIdx ? startIdx - endIdx : endIdx - startIdx);
345
346                                 // 繰返し方向横(列)(行がデフォルト)
347                                 if(COL.equalsIgnoreCase(direction)) {
348                                         distance *= colSpan;
349                                         // 繰返し範囲以降をずらす
350                                         ExcelUtil.shift(sheet, new CellRangeAddress(fromRange.getFirstRow(), fromRange.getLastRow(), fromRange.getLastColumn() + 1, fromRange.getLastColumn() + 1), COL, distance, block);
351                                 }
352                                 // 繰返し方向縦(行)の場合
353                                 else {
354                                         distance *= rowSpan;
355                                         // 繰返し範囲以降をずらす
356                                         ExcelUtil.shift(sheet, new CellRangeAddress(fromRange.getLastRow() + 1, fromRange.getLastRow() + 1, fromRange.getFirstColumn(), fromRange.getLastColumn()), ROW, distance, block);
357                                 }
358                         }
359                         // shift:falseの場合、コピー先範囲をクリア
360                         else {
361                                 ExcelUtil.clearRange(sheet, toRange, COPY.equalsIgnoreCase(style), COPY.equalsIgnoreCase(style));
362                         }
363                         // style:copyの場合、コピー元範囲の結合保持・解除
364                         if(COPY.equalsIgnoreCase(style)) {
365                                 // コピー元範囲の結合状態チェック・保持。コピー先範囲の結合解除
366                                 CellRangeAddress tmpRange;
367                                 for(int i = 0; i < sheet.getNumMergedRegions(); i++) {
368                                         tmpRange = sheet.getMergedRegion(i);
369                                         // コピー元範囲の結合状態保持・解除
370                                         switch(CellRangeUtil.intersect(fromRange, tmpRange)) {
371                                         case CellRangeUtil.INSIDE:
372                                                 rangeList.add(tmpRange);
373                                                 log.debug("from range inside mergedRegion. save: {}", tmpRange.formatAsString());
374                                                 break;
375                                         case CellRangeUtil.ENCLOSES:
376                                                 log.warn("from range encloses mergedRegion. remove: {}", tmpRange.formatAsString());
377                                                 sheet.removeMergedRegion(i);
378                                                 break;
379                                         case CellRangeUtil.OVERLAP:
380                                                 log.warn("from range overlap mergedRegion. remove: {}", tmpRange.formatAsString());
381                                                 sheet.removeMergedRegion(i);
382                                                 break;
383                                         }
384                                 }
385                         }
386                 }
387
388                 // 範囲行でループ
389                 for(int r = fromRange.getFirstRow(); r <= fromRange.getLastRow(); r++) {
390                         // コピー元行
391                         fromRow = sheet.getRow(r);
392                         // コピー行
393                         toRow = fromRow;
394                         // 範囲列でループ
395                         colLoop:
396                         for(int c = fromRange.getFirstColumn(); c <= fromRange.getLastColumn(); c++) {
397                                 // コピー元セル
398                                 fromCell = fromRow == null ? null : fromRow.getCell(c);
399                                 // コピー元セルが数式か文字列の場合バリュー保持
400                                 fromCellValue = null;
401                                 if(fromCell != null && (fromCell.getCellType() == Cell.CELL_TYPE_FORMULA || fromCell.getCellType() == Cell.CELL_TYPE_STRING)) {
402                                         switch(fromCell.getCellType()) {
403                                         case Cell.CELL_TYPE_FORMULA:
404                                                 fromCellValue = fromCell.getCellFormula();
405                                                 break;
406                                         case Cell.CELL_TYPE_STRING:
407                                                 fromCellValue = fromCell.getStringCellValue();
408                                         }
409                                         // 正規表現オブジェクト
410                                         pattern = Pattern.compile("(" + Pattern.quote("${") + "[^\\$\\{\\}]*?\\b+)(" + Pattern.quote(object) + ")([^a-zA-Z_0-9\\$]+?)");
411                                         matcher = pattern.matcher(fromCellValue);
412                                 }
413                                 
414                                 // 繰返し回数でループしコピー
415                                 for(int i = startIdx, cpCount = 0; (startIdx <= endIdx && i <= endIdx || startIdx > endIdx && i >= endIdx); i = (startIdx <= endIdx ? i + 1 : i - 1), cpCount++) {
416                                         // 繰返し方向横(列)(行がデフォルト)
417                                         if(COL.equalsIgnoreCase(direction)) {
418                                                 // コピー先の範囲チェック
419                                                 if(c + colSpan * cpCount > ExcelUtil.getMaxColumnIndex(sheet)) {
420                                                         // コピー先列がシート範囲外
421                                                         log.debug("break col loop. to cell [{}] is outside sheet", c + colSpan * cpCount + 1);
422                                                         break colLoop;
423                                                 }
424                                                 // コピー元行がnullならコピー先行もnull
425                                                 if(fromRow == null) {
426                                                         log.debug("break col loop. from row [{}] and to row [{}] is null", (r + 1), (r + 1));
427                                                         break colLoop;
428                                                 } 
429                                         }
430                                         // 繰返し方向縦(行)の場合
431                                         else {
432                                                 // コピー先の範囲チェック
433                                                 if(r + rowSpan * cpCount > ExcelUtil.getMaxRowIndex(sheet)) {
434                                                         // コピー先行がシート範囲外
435                                                         log.debug("break copy loop. to row [{}] is outside sheet", r + rowSpan * cpCount + 1);
436                                                         break;
437                                                 }
438                                                 // コピー行
439                                                 toRow = sheet.getRow(r + rowSpan * cpCount);
440                                                 // コピー元行がnullならコピー先行もnull。continue
441                                                 if(fromRow == null) {
442                                                         if(toRow != null) {
443                                                                 log.debug("continue. from row [{}] is null. to row [{}] remove", (r + 1), (toRow.getRowNum() + 1));
444                                                                 sheet.removeRow(toRow);
445                                                         }
446                                                         else {
447                                                                 log.debug("continue. from row [{}] and to row [{}] is null", (r + 1), ((ROW.equalsIgnoreCase(direction) ? (r + rowSpan * cpCount) : r) + 1));
448                                                         }
449                                                         continue;
450                                                 } 
451                                         }
452
453                                         // コピー先行がnullなら生成
454                                         if(toRow == null) toRow = sheet.createRow(r + rowSpan * cpCount);
455
456                                         // コピー元行・コピー先行 行番号が異なり、block false、繰返し方向縦(行)なら行情報(高さ)もコピー(範囲列先頭のみ)
457                                         if(cpCount > 0 && !block && c == fromRange.getFirstColumn() && ROW.equalsIgnoreCase(direction))
458                                                 toRow.setHeight(fromRow.getHeight());
459
460                                         // コピー先セル
461                                         toCell = toRow.getCell(COL.equalsIgnoreCase(direction) ? c + colSpan * cpCount : c);
462                                         // コピー元セルがnullならコピー先セルもnull
463                                         if(fromCell == null) {
464                                                 if(toCell != null) {
465                                                         log.debug("continue. from cell [{}] is null. to cell [{}] remove", (new CellReference(fromRow.getRowNum(), c)).formatAsString(), (new CellReference(toCell.getRowIndex(), toCell.getColumnIndex())).formatAsString());
466                                                         toRow.removeCell(toCell);
467                                                 }
468                                                 else {
469                                                         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());
470                                                 }
471                                                 continue;
472                                         }
473                                         // コピー先セルがnullなら生成
474                                         if(toCell == null) toCell = toRow.createCell(COL.equalsIgnoreCase(direction) ? c + colSpan * cpCount : c);
475
476                                         // コピー元列・コピー先列 列番号が異なり、block false、繰返し方向横(列)なら列情報(幅)もコピー(範囲行先頭のみ)
477                                         if(cpCount > 0 && !block && r == fromRange.getFirstRow() && COL.equalsIgnoreCase(direction))
478                                                 sheet.setColumnWidth(toCell.getColumnIndex(), sheet.getColumnWidth(fromCell.getColumnIndex()));
479
480                                         // スタイルコピーなら
481                                         if(cpCount > 0  && COPY.equalsIgnoreCase(style)) {
482                                                 // スタイルのコピー
483                                                 toCell.setCellStyle(fromCell.getCellStyle());
484                                         }
485                                         // 値のコピー
486                                         switch(fromCell.getCellType()) {
487                                         case Cell.CELL_TYPE_BLANK:
488                                                 toCell.setCellType(Cell.CELL_TYPE_BLANK);
489                                                 break;
490                                         case Cell.CELL_TYPE_BOOLEAN:
491                                                 toCell.setCellType(Cell.CELL_TYPE_BOOLEAN);
492                                                 toCell.setCellValue(fromCell.getBooleanCellValue());
493                                                 break;
494                                         case Cell.CELL_TYPE_ERROR:
495                                                 toCell.setCellType(Cell.CELL_TYPE_ERROR);
496                                                 toCell.setCellErrorValue(fromCell.getErrorCellValue());
497                                                 break;
498                                         case Cell.CELL_TYPE_NUMERIC:
499                                                 toCell.setCellType(Cell.CELL_TYPE_NUMERIC);
500                                                 toCell.setCellValue(fromCell.getNumericCellValue());
501                                                 break;
502                                         case Cell.CELL_TYPE_FORMULA:
503                                                 toCell.setCellType(Cell.CELL_TYPE_FORMULA);
504                                                 // 数式のパース・移動先に合わせる
505                                                 toCell.setCellFormula(
506                                                                 ExcelUtil.getMoveFormula(
507                                                                                 sheet, 
508                                                                                 matcher.replaceAll("$1" + Matcher.quoteReplacement("(" + list + ")[" + (mapKeys == null ? i - 1 : "'" + mapKeys[i - 1] + "'") + "]") + "$3"),
509                                                                                 toCell.getRowIndex() - fromCell.getRowIndex(), 
510                                                                                 toCell.getColumnIndex() - fromCell.getColumnIndex()
511                                                                 )
512                                                 );
513                                                 log.debug("to cell Formula: {}", toCell.getCellFormula());
514                                                 break;
515                                         case Cell.CELL_TYPE_STRING:
516                                                 toCell.setCellType(Cell.CELL_TYPE_STRING);
517 //                                              log.debug("fromCell   : {}", fromCell.getStringCellValue());
518 //                                              log.debug("toCell     : {}", toCell.getStringCellValue());
519 //                                              log.debug("i          : {}", i);
520 //                                              log.debug("cpCount    : {}", cpCount);
521 //                                              log.debug("regex      : {}", "(" + Pattern.quote("${") + "[^\\$\\{\\}]*?\\b+)(" + Pattern.quote(object) + ")([^a-zA-Z_0-9\\$]+?)");
522 //                                              log.debug("replacement: {}", "$1" + Matcher.quoteReplacement("(" + list + ")[" + (mapKeys == null ? i - 1 : "'" + mapKeys[i - 1] + "'") + "]") + "$3");
523 //                                              log.debug("replaceAll:  {}", matcher.replaceAll("$1" + Matcher.quoteReplacement("(" + list + ")[" + (mapKeys == null ? i - 1 : "'" + mapKeys[i - 1] + "'") + "]") + "$3"));
524                                                 toCell.setCellValue(matcher.replaceAll("$1" + Matcher.quoteReplacement("(" + list + ")[" + (mapKeys == null ? i - 1 : "'" + mapKeys[i - 1] + "'") + "]") + "$3"));
525                                                 log.debug("to cell string: {}", toCell.getStringCellValue());
526                                                 break;
527                                         }
528                                 }
529                         }
530                 }
531
532                 // スタイルコピーなら
533                 if(COPY.equalsIgnoreCase(style)) {
534                         // 行列加算用
535                         int addRow = 0;
536                         int addCol = 0;
537                         if(COL.equalsIgnoreCase(direction)) {
538                                 addCol = colSpan;
539                         }
540                         else {
541                                 addRow = rowSpan;
542                         }
543                         
544                         // コピー元範囲の結合保持なら
545                         if(!rangeList.isEmpty()) {
546                                 // 結合をコピー
547                                 // 結合保持数でループ
548                                 for(int c = 0; c < rangeList.size(); c++) {
549                                         tmpBfRange = rangeList.get(c);
550                                         // 繰返し回数でループ
551                                         for(int i = startIdx, cpCount = 0; (startIdx <= endIdx && i <= endIdx || startIdx > endIdx && i >= endIdx); i = (startIdx <= endIdx ? i + 1 : i - 1), cpCount++) {
552                                                 // 初回はコピーしない(コピー元だから)
553                                                 if(i == startIdx) continue;
554                                                 // コピー先レンジ
555                                                 tmpAfRange = new CellRangeAddress(
556                                                                 tmpBfRange.getFirstRow() + (addRow * cpCount),
557                                                                 tmpBfRange.getLastRow() + (addRow * cpCount),
558                                                                 tmpBfRange.getFirstColumn() + (addCol * cpCount),
559                                                                 tmpBfRange.getLastColumn() + (addCol * cpCount));
560                                                 if(ExcelUtil.validateRange(sheet, tmpAfRange)) {
561                                                         sheet.addMergedRegion(tmpAfRange);
562                                                         log.debug("mergedRegion copy. from: [{}] to: [{}]", tmpBfRange.formatAsString(), tmpAfRange.formatAsString());
563                                                 }
564                                         }
565                                 }
566                         }
567
568                         // オブジェクトのコピー Excel2007以降 ooxml形式のみ対応
569                         if(sheet instanceof XSSFSheet) {
570                                 int r1, c1, r2, c2;
571                                 CTDrawing ctDrawing;
572                                 CTTwoCellAnchor fAnchor, cpAnchor;
573                                 CTMarker from, to; 
574                                 try {
575                                         // DocumentPartでループ
576                                         for(POIXMLDocumentPart part : ((XSSFSheet)sheet).getRelations()) {
577                                                 if(part == null) continue;
578                                                 log.debug("DocumentPart class: {}", part.getClass().getName());
579                                                 // DocumentPartがDrawingオブジェクトの場合
580                                                 if(part instanceof XSSFDrawing) {
581                                                         ctDrawing = ((XSSFDrawing) part).getCTDrawing();
582                                                         if(ctDrawing != null) {
583                                                                 // アンカーでループ
584                                                                 int alSize = ctDrawing.getTwoCellAnchorList().size();
585                                                                 for (int i = 0; i < alSize; i++) {
586                                                                         fAnchor = ctDrawing.getTwoCellAnchorList().get(i);
587                                                                         // GraphicFrameをもつグラフ、スマートアートは現状非対応
588                                                                         if(fAnchor.isSetGraphicFrame()) continue;
589                                                                         
590                                                                         // アンカーの位置情報
591                                                                         from = fAnchor.getFrom();
592                                                                         r1 = from.getRow();
593                                                                         c1 = from.getCol();
594                                                                         to = fAnchor.getTo();
595                                                                         r2 = to.getRow();
596                                                                         c2 = to.getCol();
597                                                                         tmpBfRange = new CellRangeAddress(r1, r2, c1, c2);
598                                                                         
599                                                                         // コピー元レンジに含まれている、掛かっているならコピー
600                                                                         switch(CellRangeUtil.intersect(fromRange, tmpBfRange)) {
601                                                                         case CellRangeUtil.INSIDE:
602                                                                         case CellRangeUtil.OVERLAP:
603                                                                                 // 繰返し回数でループ
604                                                                                 for(int j = startIdx, cpCount = 0; (startIdx <= endIdx && j <= endIdx || startIdx > endIdx && j >= endIdx); j = (startIdx <= endIdx ? j + 1 : j - 1), cpCount++) {
605                                                                                         // 初回はコピーしない(コピー元だから)
606                                                                                         if(j == startIdx) continue;
607                                                                                         // オブジェクト(アンカー)のコピー
608                                                                                         cpAnchor = ctDrawing.addNewTwoCellAnchor();
609                                                                                         cpAnchor.set(fAnchor.copy());
610                                                                                         from = cpAnchor.getFrom();
611                                                                                         from.setRow(from.getRow() + (addRow * cpCount));
612                                                                                         from.setCol(from.getCol() + (addCol * cpCount));
613                                                                                         to = cpAnchor.getTo();
614                                                                                         to.setRow(to.getRow() + (addRow * cpCount));
615                                                                                         to.setCol(to.getCol() + (addCol * cpCount));
616                                                                                         if(log.isDebugEnabled()) {
617                                                                                                 tmpAfRange = new CellRangeAddress(from.getRow(), to.getRow(), from.getCol(), to.getCol());
618                                                                                                 log.debug("object copy from: [{}] to: [{}]", tmpBfRange.formatAsString(), tmpAfRange.formatAsString());
619                                                                                         }
620                                                                                 }
621                                                                         }
622                                                                 }
623                                                         }
624                                                 }
625                                         }
626                                 }
627                                 catch(Exception e) {
628                                         log.error("object copy error: " + e.getMessage(), e);
629                                 }
630                         }
631                 }
632                 
633                 log.trace("parse end");
634         }
635 }