diff --git a/.travis.yml b/.travis.yml
index 8191cf3..74750ec 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,5 +6,5 @@ cache:
before_install:
- chmod +x mvnw
install:
- - ./mvnw install -Dgpg.skip -B -V -Dmaven.test.skip=true
+ - ./mvnw install -B -V -Dmaven.test.skip=true
- ./mvnw javadoc:javadoc
\ No newline at end of file
diff --git a/README.md b/README.md
index b142b9d..ecd2000 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@ Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都
* [快速使用](https://alibaba-easyexcel.github.io/)
* [关于软件](/abouteasyexcel.md)
* [更新记事](/update.md)
+* [贡献代码](https://alibaba-easyexcel.github.io/support/contribute.html)
## 维护者
玉霄、庄家钜、怀宇
@@ -31,7 +32,7 @@ DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/ja
/**
* 最简单的读
*
1. 创建excel对应的实体对象 参照{@link DemoData}
- *
2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
+ *
2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
*
3. 直接读即可
*/
@Test
@@ -82,7 +83,7 @@ DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/ja
/**
* 文件上传
*
1. 创建excel对应的实体对象 参照{@link UploadData}
- *
2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener}
+ *
2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener}
*
3. 直接读即可
*/
@PostMapping("upload")
diff --git a/pom.xml b/pom.xml
index fe46977..4a47b3d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
com.alibaba
easyexcel
- 2.1.6
+ 2.2.0-beta1
jar
easyexcel
@@ -15,9 +15,10 @@
-
UTF-8
- 1.7
+ 1.6
+ true
+ true
@@ -66,6 +67,11 @@
poi-ooxml
3.17
+
+ org.apache.poi
+ poi-ooxml-schemas
+ 3.17
+
cglib
cglib
@@ -79,7 +85,7 @@
org.ehcache
ehcache
- 3.7.1
+ 3.4.0
@@ -154,6 +160,8 @@
com/alibaba/excel/event/AnalysisEventListener.java
+ com/alibaba/excel/metadata/DataFormatter.java
+ com/alibaba/excel/util/DateUtils.java
@@ -196,7 +204,6 @@
-
org.apache.maven.plugins
maven-gpg-plugin
diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
index eb4f188..5487ee1 100644
--- a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
+++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
@@ -14,15 +14,22 @@ import org.slf4j.LoggerFactory;
import com.alibaba.excel.analysis.v03.XlsSaxAnalyser;
import com.alibaba.excel.analysis.v07.XlsxSaxAnalyser;
import com.alibaba.excel.context.AnalysisContext;
-import com.alibaba.excel.context.AnalysisContextImpl;
+import com.alibaba.excel.context.xls.DefaultXlsReadContext;
+import com.alibaba.excel.context.xls.XlsReadContext;
+import com.alibaba.excel.context.xlsx.DefaultXlsxReadContext;
+import com.alibaba.excel.context.xlsx.XlsxReadContext;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelAnalysisStopException;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.read.metadata.ReadWorkbook;
import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
+import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder;
+import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.CollectionUtils;
+import com.alibaba.excel.util.DateUtils;
import com.alibaba.excel.util.FileUtils;
+import com.alibaba.excel.util.NumberDataFormatterUtils;
import com.alibaba.excel.util.StringUtils;
/**
@@ -41,8 +48,7 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
public ExcelAnalyserImpl(ReadWorkbook readWorkbook) {
try {
- analysisContext = new AnalysisContextImpl(readWorkbook);
- choiceExcelExecutor();
+ choiceExcelExecutor(readWorkbook);
} catch (RuntimeException e) {
finish();
throw e;
@@ -52,29 +58,25 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
}
}
- private void choiceExcelExecutor() throws Exception {
- ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder();
- ExcelTypeEnum excelType = readWorkbookHolder.getExcelType();
- if (excelType == null) {
- excelReadExecutor = new XlsxSaxAnalyser(analysisContext, null);
- return;
- }
+ private void choiceExcelExecutor(ReadWorkbook readWorkbook) throws Exception {
+ ExcelTypeEnum excelType = ExcelTypeEnum.valueOf(readWorkbook);
switch (excelType) {
case XLS:
POIFSFileSystem poifsFileSystem;
- if (readWorkbookHolder.getFile() != null) {
- poifsFileSystem = new POIFSFileSystem(readWorkbookHolder.getFile());
+ if (readWorkbook.getFile() != null) {
+ poifsFileSystem = new POIFSFileSystem(readWorkbook.getFile());
} else {
- poifsFileSystem = new POIFSFileSystem(readWorkbookHolder.getInputStream());
+ poifsFileSystem = new POIFSFileSystem(readWorkbook.getInputStream());
}
// So in encrypted excel, it looks like XLS but it's actually XLSX
if (poifsFileSystem.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) {
InputStream decryptedStream = null;
try {
- decryptedStream =
- DocumentFactoryHelper.getDecryptedStream(poifsFileSystem.getRoot().getFileSystem(),
- analysisContext.readWorkbookHolder().getPassword());
- excelReadExecutor = new XlsxSaxAnalyser(analysisContext, decryptedStream);
+ decryptedStream = DocumentFactoryHelper
+ .getDecryptedStream(poifsFileSystem.getRoot().getFileSystem(), readWorkbook.getPassword());
+ XlsxReadContext xlsxReadContext = new DefaultXlsxReadContext(readWorkbook, ExcelTypeEnum.XLSX);
+ analysisContext = xlsxReadContext;
+ excelReadExecutor = new XlsxSaxAnalyser(xlsxReadContext, decryptedStream);
return;
} finally {
IOUtils.closeQuietly(decryptedStream);
@@ -83,15 +85,21 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
poifsFileSystem.close();
}
}
- if (analysisContext.readWorkbookHolder().getPassword() != null) {
- Biff8EncryptionKey.setCurrentUserPassword(analysisContext.readWorkbookHolder().getPassword());
+ if (readWorkbook.getPassword() != null) {
+ Biff8EncryptionKey.setCurrentUserPassword(readWorkbook.getPassword());
}
- excelReadExecutor = new XlsSaxAnalyser(analysisContext, poifsFileSystem);
+ XlsReadContext xlsReadContext = new DefaultXlsReadContext(readWorkbook, ExcelTypeEnum.XLS);
+ xlsReadContext.xlsReadWorkbookHolder().setPoifsFileSystem(poifsFileSystem);
+ analysisContext = xlsReadContext;
+ excelReadExecutor = new XlsSaxAnalyser(xlsReadContext);
break;
case XLSX:
- excelReadExecutor = new XlsxSaxAnalyser(analysisContext, null);
+ XlsxReadContext xlsxReadContext = new DefaultXlsxReadContext(readWorkbook, ExcelTypeEnum.XLSX);
+ analysisContext = xlsxReadContext;
+ excelReadExecutor = new XlsxSaxAnalyser(xlsxReadContext, null);
break;
default:
+ break;
}
}
@@ -101,19 +109,15 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
if (!readAll && CollectionUtils.isEmpty(readSheetList)) {
throw new IllegalArgumentException("Specify at least one read sheet.");
}
+ analysisContext.readWorkbookHolder().setParameterSheetDataList(readSheetList);
+ analysisContext.readWorkbookHolder().setReadAll(readAll);
try {
- excelReadExecutor.execute(readSheetList, readAll);
+ excelReadExecutor.execute();
} catch (ExcelAnalysisStopException e) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Custom stop!");
}
}
- // The last sheet is read
- if (excelReadExecutor instanceof XlsSaxAnalyser) {
- if (analysisContext.readSheetHolder() != null) {
- analysisContext.readSheetHolder().notifyAfterAllAnalysed(analysisContext);
- }
- }
} catch (RuntimeException e) {
finish();
throw e;
@@ -144,15 +148,17 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
throwable = t;
}
try {
- if (readWorkbookHolder.getOpcPackage() != null) {
- readWorkbookHolder.getOpcPackage().revert();
+ if ((readWorkbookHolder instanceof XlsxReadWorkbookHolder)
+ && ((XlsxReadWorkbookHolder)readWorkbookHolder).getOpcPackage() != null) {
+ ((XlsxReadWorkbookHolder)readWorkbookHolder).getOpcPackage().revert();
}
} catch (Throwable t) {
throwable = t;
}
try {
- if (readWorkbookHolder.getPoifsFileSystem() != null) {
- readWorkbookHolder.getPoifsFileSystem().close();
+ if ((readWorkbookHolder instanceof XlsReadWorkbookHolder)
+ && ((XlsReadWorkbookHolder)readWorkbookHolder).getPoifsFileSystem() != null) {
+ ((XlsReadWorkbookHolder)readWorkbookHolder).getPoifsFileSystem().close();
}
} catch (Throwable t) {
throwable = t;
@@ -175,11 +181,18 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
clearEncrypt03();
+ removeThreadLocalCache();
+
if (throwable != null) {
throw new ExcelAnalysisException("Can not close IO.", throwable);
}
}
+ private void removeThreadLocalCache() {
+ NumberDataFormatterUtils.removeThreadLocalCache();
+ DateUtils.removeThreadLocalCache();
+ }
+
private void clearEncrypt03() {
if (StringUtils.isEmpty(analysisContext.readWorkbookHolder().getPassword())
|| !ExcelTypeEnum.XLS.equals(analysisContext.readWorkbookHolder().getExcelType())) {
diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelReadExecutor.java b/src/main/java/com/alibaba/excel/analysis/ExcelReadExecutor.java
index 10ced98..085caab 100644
--- a/src/main/java/com/alibaba/excel/analysis/ExcelReadExecutor.java
+++ b/src/main/java/com/alibaba/excel/analysis/ExcelReadExecutor.java
@@ -20,11 +20,6 @@ public interface ExcelReadExecutor {
/**
* Read the sheet.
- *
- * @param readSheetList
- * Which sheets you need to read.
- * @param readAll
- * The readSheetList
parameter is ignored, and all sheets are read.
*/
- void execute(List readSheetList, Boolean readAll);
+ void execute();
}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java
deleted file mode 100644
index 6128708..0000000
--- a/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.alibaba.excel.analysis.v03;
-
-import com.alibaba.excel.metadata.CellData;
-
-/**
- *
- * @author Dan Zheng
- */
-public abstract class AbstractXlsRecordHandler implements XlsRecordHandler {
- protected int row = -1;
- protected int column = -1;
- protected CellData cellData;
-
- @Override
- public int getRow() {
- return row;
- }
-
- @Override
- public int getColumn() {
- return column;
- }
-
- @Override
- public CellData getCellData() {
- return cellData;
- }
-
- @Override
- public int compareTo(XlsRecordHandler o) {
- return this.getOrder() - o.getOrder();
- }
-}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/IgnorableXlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/IgnorableXlsRecordHandler.java
new file mode 100644
index 0000000..cb7e4a8
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v03/IgnorableXlsRecordHandler.java
@@ -0,0 +1,8 @@
+package com.alibaba.excel.analysis.v03;
+
+/**
+ * Need to ignore the current handler without reading the current sheet.
+ *
+ * @author Jiaju Zhuang
+ */
+public interface IgnorableXlsRecordHandler extends XlsRecordHandler {}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java
index 6f8e716..cfdc6be 100644
--- a/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java
+++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java
@@ -1,8 +1,8 @@
package com.alibaba.excel.analysis.v03;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder;
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
@@ -10,13 +10,14 @@ import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
import org.apache.poi.hssf.eventusermodel.HSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFRequest;
import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener;
+import org.apache.poi.hssf.record.BOFRecord;
+import org.apache.poi.hssf.record.BoundSheetRecord;
import org.apache.poi.hssf.record.Record;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import com.alibaba.excel.analysis.v03.handlers.BofRecordHandler;
-import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.analysis.v03.handlers.BoundSheetRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
import com.alibaba.excel.exception.ExcelAnalysisException;
-import com.alibaba.excel.read.metadata.ReadSheet;
/**
* In some cases, you need to know the number of sheets in advance and only read the file once in advance.
@@ -24,24 +25,29 @@ import com.alibaba.excel.read.metadata.ReadSheet;
* @author Jiaju Zhuang
*/
public class XlsListSheetListener implements HSSFListener {
- private POIFSFileSystem poifsFileSystem;
- private List sheetList;
- private BofRecordHandler bofRecordHandler;
-
- public XlsListSheetListener(AnalysisContext analysisContext, POIFSFileSystem poifsFileSystem) {
- this.poifsFileSystem = poifsFileSystem;
- sheetList = new ArrayList();
- bofRecordHandler = new BofRecordHandler(analysisContext, sheetList, false, false);
- bofRecordHandler.init();
- bofRecordHandler.init(null, true);
+ private XlsReadContext xlsReadContext;
+ private static final Map XLS_RECORD_HANDLER_MAP = new HashMap();
+
+ static {
+ XLS_RECORD_HANDLER_MAP.put(BOFRecord.sid, new BofRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(BoundSheetRecord.sid, new BoundSheetRecordHandler());
+ }
+
+ public XlsListSheetListener(XlsReadContext xlsReadContext) {
+ this.xlsReadContext = xlsReadContext;
+ xlsReadContext.xlsReadWorkbookHolder().setNeedReadSheet(Boolean.FALSE);
}
@Override
public void processRecord(Record record) {
- bofRecordHandler.processRecord(record);
+ XlsRecordHandler handler = XLS_RECORD_HANDLER_MAP.get(record.getSid());
+ if (handler == null) {
+ return;
+ }
+ handler.processRecord(xlsReadContext, record);
}
- public List getSheetList() {
+ public void execute() {
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
HSSFListener formatListener = new FormatTrackingHSSFListener(listener);
HSSFEventFactory factory = new HSSFEventFactory();
@@ -49,12 +55,10 @@ public class XlsListSheetListener implements HSSFListener {
EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener =
new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener);
request.addListenerForAllRecords(workbookBuildingListener);
-
try {
- factory.processWorkbookEvents(request, poifsFileSystem);
+ factory.processWorkbookEvents(request, xlsReadContext.xlsReadWorkbookHolder().getPoifsFileSystem());
} catch (IOException e) {
throw new ExcelAnalysisException(e);
}
- return sheetList;
}
}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java
index b786bcb..ca9218a 100644
--- a/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java
+++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java
@@ -2,60 +2,28 @@ package com.alibaba.excel.analysis.v03;
import org.apache.poi.hssf.record.Record;
-import com.alibaba.excel.metadata.CellData;
+import com.alibaba.excel.context.xls.XlsReadContext;
/**
* Intercepts handle xls reads.
*
* @author Dan Zheng
*/
-public interface XlsRecordHandler extends Comparable {
+public interface XlsRecordHandler {
/**
- * Which tags are supported
+ * Whether to support
*
+ * @param xlsReadContext
* @param record
- * Excel analysis record
- * @return Which tags are supported
+ * @return
*/
- boolean support(Record record);
-
- /**
- * Initialize
- */
- void init();
+ boolean support(XlsReadContext xlsReadContext, Record record);
/**
* Processing record
*
+ * @param xlsReadContext
* @param record
*/
- void processRecord(Record record);
-
- /**
- * Get row
- *
- * @return Row index
- */
- int getRow();
-
- /**
- * Get column
- *
- * @return Column index
- */
- int getColumn();
-
- /**
- * Get value
- *
- * @return Excel internal cell data
- */
- CellData getCellData();
-
- /**
- * Get order
- *
- * @return Order
- */
- int getOrder();
+ void processRecord(XlsReadContext xlsReadContext, Record record);
}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java
index e0c150c..2b92253 100644
--- a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java
+++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java
@@ -1,12 +1,9 @@
package com.alibaba.excel.analysis.v03;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashMap;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.TreeMap;
import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder;
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
@@ -16,32 +13,52 @@ import org.apache.poi.hssf.eventusermodel.HSSFRequest;
import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener;
import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
import org.apache.poi.hssf.record.BOFRecord;
+import org.apache.poi.hssf.record.BlankRecord;
+import org.apache.poi.hssf.record.BoolErrRecord;
import org.apache.poi.hssf.record.BoundSheetRecord;
+import org.apache.poi.hssf.record.EOFRecord;
+import org.apache.poi.hssf.record.FormulaRecord;
+import org.apache.poi.hssf.record.HyperlinkRecord;
+import org.apache.poi.hssf.record.IndexRecord;
+import org.apache.poi.hssf.record.LabelRecord;
+import org.apache.poi.hssf.record.LabelSSTRecord;
+import org.apache.poi.hssf.record.MergeCellsRecord;
+import org.apache.poi.hssf.record.NoteRecord;
+import org.apache.poi.hssf.record.NumberRecord;
+import org.apache.poi.hssf.record.ObjRecord;
+import org.apache.poi.hssf.record.RKRecord;
import org.apache.poi.hssf.record.Record;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.hssf.record.SSTRecord;
+import org.apache.poi.hssf.record.StringRecord;
+import org.apache.poi.hssf.record.TextObjectRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.analysis.ExcelReadExecutor;
-import com.alibaba.excel.analysis.v03.handlers.BlankOrErrorRecordHandler;
+import com.alibaba.excel.analysis.v03.handlers.BlankRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.BofRecordHandler;
+import com.alibaba.excel.analysis.v03.handlers.BoolErrRecordHandler;
+import com.alibaba.excel.analysis.v03.handlers.BoundSheetRecordHandler;
+import com.alibaba.excel.analysis.v03.handlers.DummyRecordHandler;
+import com.alibaba.excel.analysis.v03.handlers.EofRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.FormulaRecordHandler;
+import com.alibaba.excel.analysis.v03.handlers.HyperlinkRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.IndexRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.LabelRecordHandler;
-import com.alibaba.excel.analysis.v03.handlers.MissingCellDummyRecordHandler;
+import com.alibaba.excel.analysis.v03.handlers.LabelSstRecordHandler;
+import com.alibaba.excel.analysis.v03.handlers.MergeCellsRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.NoteRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.NumberRecordHandler;
+import com.alibaba.excel.analysis.v03.handlers.ObjRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.RkRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.SstRecordHandler;
-import com.alibaba.excel.context.AnalysisContext;
-import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.analysis.v03.handlers.StringRecordHandler;
+import com.alibaba.excel.analysis.v03.handlers.TextObjectRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
import com.alibaba.excel.exception.ExcelAnalysisException;
-import com.alibaba.excel.metadata.CellData;
-import com.alibaba.excel.read.listener.event.EachRowAnalysisFinishEvent;
+import com.alibaba.excel.exception.ExcelAnalysisStopException;
import com.alibaba.excel.read.metadata.ReadSheet;
-import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
-import com.alibaba.excel.util.CollectionUtils;
+import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder;
/**
* /** * A text extractor for Excel files. *
@@ -60,168 +77,90 @@ import com.alibaba.excel.util.CollectionUtils;
*/
public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor {
private static final Logger LOGGER = LoggerFactory.getLogger(XlsSaxAnalyser.class);
+ private static final short DUMMY_RECORD_SID = -1;
+ private XlsReadContext xlsReadContext;
+ private static final Map XLS_RECORD_HANDLER_MAP = new HashMap(32);
+
+ static {
+ XLS_RECORD_HANDLER_MAP.put(BlankRecord.sid, new BlankRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(BOFRecord.sid, new BofRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(BoolErrRecord.sid, new BoolErrRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(BoundSheetRecord.sid, new BoundSheetRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(DUMMY_RECORD_SID, new DummyRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(EOFRecord.sid, new EofRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(FormulaRecord.sid, new FormulaRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(HyperlinkRecord.sid, new HyperlinkRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(IndexRecord.sid, new IndexRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(LabelRecord.sid, new LabelRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(LabelSSTRecord.sid, new LabelSstRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(MergeCellsRecord.sid, new MergeCellsRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(NoteRecord.sid, new NoteRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(NumberRecord.sid, new NumberRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(ObjRecord.sid, new ObjRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(RKRecord.sid, new RkRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(SSTRecord.sid, new SstRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(StringRecord.sid, new StringRecordHandler());
+ XLS_RECORD_HANDLER_MAP.put(TextObjectRecord.sid, new TextObjectRecordHandler());
+ }
- private POIFSFileSystem poifsFileSystem;
- private Boolean readAll;
- private List readSheetList;
- private int lastRowNumber;
- private int lastColumnNumber;
- /**
- * For parsing Formulas
- */
- private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener;
- private FormatTrackingHSSFListener formatListener;
- private Map records;
- private List sheets;
- private HSSFWorkbook stubWorkbook;
- private List recordHandlers = new ArrayList();
- private AnalysisContext analysisContext;
-
- public XlsSaxAnalyser(AnalysisContext context, POIFSFileSystem poifsFileSystem) {
- this.analysisContext = context;
- this.records = new LinkedHashMap();
- this.poifsFileSystem = poifsFileSystem;
- analysisContext.readWorkbookHolder().setPoifsFileSystem(poifsFileSystem);
+ public XlsSaxAnalyser(XlsReadContext xlsReadContext) {
+ this.xlsReadContext = xlsReadContext;
}
@Override
public List sheetList() {
- if (sheets == null) {
- LOGGER.warn("Getting the 'sheetList' before reading will cause the file to be read twice.");
- XlsListSheetListener xlsListSheetListener = new XlsListSheetListener(analysisContext, poifsFileSystem);
- sheets = xlsListSheetListener.getSheetList();
+ try {
+ if (xlsReadContext.readWorkbookHolder().getActualSheetDataList() == null) {
+ new XlsListSheetListener(xlsReadContext).execute();
+ }
+ } catch (ExcelAnalysisStopException e) {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Custom stop!");
+ }
}
- return sheets;
+ return xlsReadContext.readWorkbookHolder().getActualSheetDataList();
}
@Override
- public void execute(List readSheetList, Boolean readAll) {
- this.readAll = readAll;
- this.readSheetList = readSheetList;
+ public void execute() {
+ XlsReadWorkbookHolder xlsReadWorkbookHolder = xlsReadContext.xlsReadWorkbookHolder();
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
- formatListener = new FormatTrackingHSSFListener(listener);
- workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener);
- if (workbookBuildingListener != null && stubWorkbook == null) {
- stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook();
- }
- init();
+ xlsReadWorkbookHolder.setFormatTrackingHSSFListener(new FormatTrackingHSSFListener(listener));
+ EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener =
+ new EventWorkbookBuilder.SheetRecordCollectingListener(
+ xlsReadWorkbookHolder.getFormatTrackingHSSFListener());
+ xlsReadWorkbookHolder.setHssfWorkbook(workbookBuildingListener.getStubHSSFWorkbook());
HSSFEventFactory factory = new HSSFEventFactory();
HSSFRequest request = new HSSFRequest();
- request.addListenerForAllRecords(formatListener);
+ request.addListenerForAllRecords(xlsReadWorkbookHolder.getFormatTrackingHSSFListener());
try {
- factory.processWorkbookEvents(request, poifsFileSystem);
+ factory.processWorkbookEvents(request, xlsReadWorkbookHolder.getPoifsFileSystem());
} catch (IOException e) {
throw new ExcelAnalysisException(e);
}
// Sometimes tables lack the end record of the last column
- if (!records.isEmpty()) {
- endRow();
+ if (!xlsReadContext.xlsReadSheetHolder().getCellMap().isEmpty()) {
+ // Forge a termination data
+ processRecord(new LastCellOfRowDummyRecord(xlsReadContext.xlsReadSheetHolder().getRowIndex() + 1, -1));
}
}
- private void init() {
- lastRowNumber = 0;
- lastColumnNumber = 0;
- records = new LinkedHashMap();
- buildXlsRecordHandlers();
- }
-
@Override
public void processRecord(Record record) {
- // Not data from the current sheet
- if (ignoreRecord(record)) {
+ XlsRecordHandler handler = XLS_RECORD_HANDLER_MAP.get(record.getSid());
+ if (handler == null) {
return;
}
- int thisRow = -1;
- int thisColumn = -1;
- CellData cellData = null;
- for (XlsRecordHandler handler : this.recordHandlers) {
- if (handler.support(record)) {
- handler.processRecord(record);
- thisRow = handler.getRow();
- thisColumn = handler.getColumn();
- cellData = handler.getCellData();
- if (cellData != null) {
- cellData.checkEmpty();
- if (CellDataTypeEnum.EMPTY != cellData.getType()) {
- records.put(thisColumn, cellData);
- }
- }
- break;
- }
- }
- // If we got something to print out, do so
- if (cellData != null && analysisContext.currentReadHolder().globalConfiguration().getAutoTrim()
- && CellDataTypeEnum.STRING == cellData.getType()) {
- cellData.setStringValue(cellData.getStringValue().trim());
- }
-
- // Handle new row
- if (thisRow != -1 && thisRow != lastRowNumber) {
- lastColumnNumber = -1;
- }
-
- // Update column and row count
- if (thisRow > -1) {
- lastRowNumber = thisRow;
- }
- if (thisColumn > -1) {
- lastColumnNumber = thisColumn;
- }
-
- processLastCellOfRow(record);
- }
-
- private boolean ignoreRecord(Record record) {
- return analysisContext.readWorkbookHolder().getIgnoreRecord03() && record.getSid() != BoundSheetRecord.sid
- && record.getSid() != BOFRecord.sid;
- }
-
- private void processLastCellOfRow(Record record) {
- // Handle end of row
- if (record instanceof LastCellOfRowDummyRecord) {
- endRow();
+ boolean ignoreRecord = (handler instanceof IgnorableXlsRecordHandler)
+ && xlsReadContext.xlsReadSheetHolder() != null && xlsReadContext.xlsReadSheetHolder().getIgnoreRecord();
+ if (ignoreRecord) {
+ // No need to read the current sheet
+ return;
}
- }
-
- private void endRow() {
- if (lastColumnNumber == -1) {
- lastColumnNumber = 0;
+ if (!handler.support(xlsReadContext, record)) {
+ return;
}
- analysisContext.readRowHolder(
- new ReadRowHolder(lastRowNumber, analysisContext.readSheetHolder().getGlobalConfiguration()));
- analysisContext.readSheetHolder().notifyEndOneRow(new EachRowAnalysisFinishEvent(records), analysisContext);
- records.clear();
- lastColumnNumber = -1;
+ handler.processRecord(xlsReadContext, record);
}
- private void buildXlsRecordHandlers() {
- if (CollectionUtils.isEmpty(recordHandlers)) {
- recordHandlers.add(new BlankOrErrorRecordHandler());
- // The table has been counted and there are no duplicate statistics
- if (sheets == null) {
- sheets = new ArrayList();
- recordHandlers.add(new BofRecordHandler(analysisContext, sheets, false, true));
- } else {
- recordHandlers.add(new BofRecordHandler(analysisContext, sheets, true, true));
- }
- recordHandlers.add(new FormulaRecordHandler(stubWorkbook, formatListener));
- recordHandlers.add(new LabelRecordHandler());
- recordHandlers.add(new NoteRecordHandler());
- recordHandlers.add(new NumberRecordHandler(formatListener));
- recordHandlers.add(new RkRecordHandler());
- recordHandlers.add(new SstRecordHandler());
- recordHandlers.add(new MissingCellDummyRecordHandler());
- recordHandlers.add(new IndexRecordHandler(analysisContext));
- Collections.sort(recordHandlers);
- }
-
- for (XlsRecordHandler x : recordHandlers) {
- x.init();
- if (x instanceof BofRecordHandler) {
- BofRecordHandler bofRecordHandler = (BofRecordHandler)x;
- bofRecordHandler.init(readSheetList, readAll);
- }
- }
- }
}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/AbstractXlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/AbstractXlsRecordHandler.java
new file mode 100644
index 0000000..93b3d1a
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/AbstractXlsRecordHandler.java
@@ -0,0 +1,19 @@
+package com.alibaba.excel.analysis.v03.handlers;
+
+import org.apache.poi.hssf.record.Record;
+
+import com.alibaba.excel.analysis.v03.XlsRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
+
+/**
+ * Abstract xls record handler
+ *
+ * @author Jiaju Zhuang
+ **/
+public abstract class AbstractXlsRecordHandler implements XlsRecordHandler {
+
+ @Override
+ public boolean support(XlsReadContext xlsReadContext, Record record) {
+ return true;
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java
deleted file mode 100644
index f64d437..0000000
--- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.alibaba.excel.analysis.v03.handlers;
-
-import org.apache.poi.hssf.record.BlankRecord;
-import org.apache.poi.hssf.record.BoolErrRecord;
-import org.apache.poi.hssf.record.Record;
-
-import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
-import com.alibaba.excel.enums.CellDataTypeEnum;
-import com.alibaba.excel.metadata.CellData;
-
-/**
- * Record handler
- *
- * @author Dan Zheng
- */
-public class BlankOrErrorRecordHandler extends AbstractXlsRecordHandler {
-
- @Override
- public boolean support(Record record) {
- return BlankRecord.sid == record.getSid() || BoolErrRecord.sid == record.getSid();
- }
-
- @Override
- public void processRecord(Record record) {
- if (record.getSid() == BlankRecord.sid) {
- BlankRecord br = (BlankRecord)record;
- this.row = br.getRow();
- this.column = br.getColumn();
- this.cellData = new CellData(CellDataTypeEnum.EMPTY);
- } else if (record.getSid() == BoolErrRecord.sid) {
- BoolErrRecord ber = (BoolErrRecord)record;
- this.row = ber.getRow();
- this.column = ber.getColumn();
- this.cellData = new CellData(ber.getBooleanValue());
- }
- }
-
- @Override
- public void init() {
-
- }
-
- @Override
- public int getOrder() {
- return 0;
- }
-}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankRecordHandler.java
new file mode 100644
index 0000000..e6290eb
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankRecordHandler.java
@@ -0,0 +1,23 @@
+package com.alibaba.excel.analysis.v03.handlers;
+
+import org.apache.poi.hssf.record.BlankRecord;
+import org.apache.poi.hssf.record.Record;
+
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
+import com.alibaba.excel.metadata.CellData;
+
+/**
+ * Record handler
+ *
+ * @author Dan Zheng
+ */
+public class BlankRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
+
+ @Override
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ BlankRecord br = (BlankRecord)record;
+ xlsReadContext.xlsReadSheetHolder().getCellMap().put((int)br.getColumn(),
+ CellData.newEmptyInstance(br.getRow(), (int)br.getColumn()));
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java
index 083edbc..66e3ab7 100644
--- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java
@@ -7,9 +7,10 @@ import org.apache.poi.hssf.record.BOFRecord;
import org.apache.poi.hssf.record.BoundSheetRecord;
import org.apache.poi.hssf.record.Record;
-import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
-import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.context.xls.XlsReadContext;
+import com.alibaba.excel.exception.ExcelAnalysisStopException;
import com.alibaba.excel.read.metadata.ReadSheet;
+import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder;
import com.alibaba.excel.util.SheetUtils;
/**
@@ -18,91 +19,55 @@ import com.alibaba.excel.util.SheetUtils;
* @author Dan Zheng
*/
public class BofRecordHandler extends AbstractXlsRecordHandler {
- private List boundSheetRecords = new ArrayList();
- private BoundSheetRecord[] orderedBsrs;
- private int sheetIndex;
- private List sheets;
- private Boolean readAll;
- private List readSheetList;
- private AnalysisContext context;
- private boolean alreadyInit;
- private boolean needInitSheet;
-
- public BofRecordHandler(AnalysisContext context, List sheets, boolean alreadyInit,
- boolean needInitSheet) {
- this.context = context;
- this.sheets = sheets;
- this.alreadyInit = alreadyInit;
- this.needInitSheet = needInitSheet;
- }
-
- @Override
- public boolean support(Record record) {
- return BoundSheetRecord.sid == record.getSid() || BOFRecord.sid == record.getSid();
- }
@Override
- public void processRecord(Record record) {
- if (record.getSid() == BoundSheetRecord.sid) {
- boundSheetRecords.add((BoundSheetRecord)record);
- } else if (record.getSid() == BOFRecord.sid) {
- BOFRecord br = (BOFRecord)record;
- if (br.getType() == BOFRecord.TYPE_WORKSHEET) {
- if (orderedBsrs == null) {
- orderedBsrs = BoundSheetRecord.orderByBofPosition(boundSheetRecords);
- }
- String sheetName = orderedBsrs[sheetIndex].getSheetname();
- // Find the currently read sheet
- ReadSheet readSheet = null;
- if (!alreadyInit) {
- readSheet = new ReadSheet(sheetIndex, sheetName);
- sheets.add(readSheet);
- }
- if (needInitSheet) {
- if (readSheet == null) {
- for (ReadSheet sheet : sheets) {
- if (sheet.getSheetNo() == sheetIndex) {
- readSheet = sheet;
- break;
- }
- }
- }
- assert readSheet != null : "Can't find the sheet.";
- context.readWorkbookHolder().setIgnoreRecord03(Boolean.TRUE);
- // Copy the parameter to the current sheet
- readSheet = SheetUtils.match(readSheet, readSheetList, readAll,
- context.readWorkbookHolder().getGlobalConfiguration());
- if (readSheet != null) {
- if (readSheet.getSheetNo() != 0 && context.readSheetHolder() != null) {
- // Prompt for the end of the previous form read
- context.readSheetHolder().notifyAfterAllAnalysed(context);
- }
- context.currentSheet(readSheet);
- context.readWorkbookHolder().setIgnoreRecord03(Boolean.FALSE);
- }
- }
- sheetIndex++;
- }
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ BOFRecord br = (BOFRecord)record;
+ XlsReadWorkbookHolder xlsReadWorkbookHolder = xlsReadContext.xlsReadWorkbookHolder();
+ if (br.getType() == BOFRecord.TYPE_WORKBOOK) {
+ xlsReadWorkbookHolder.setReadSheetIndex(null);
+ return;
}
- }
-
- @Override
- public void init() {
- sheetIndex = 0;
- orderedBsrs = null;
- boundSheetRecords.clear();
- if (!alreadyInit) {
- sheets.clear();
+ if (br.getType() != BOFRecord.TYPE_WORKSHEET) {
+ return;
}
+ // Init read sheet Data
+ initReadSheetDataList(xlsReadWorkbookHolder);
+ Integer readSheetIndex = xlsReadWorkbookHolder.getReadSheetIndex();
+ if (readSheetIndex == null) {
+ readSheetIndex = 0;
+ xlsReadWorkbookHolder.setReadSheetIndex(readSheetIndex);
+ }
+ ReadSheet readSheet = xlsReadWorkbookHolder.getActualSheetDataList().get(readSheetIndex);
+ assert readSheet != null : "Can't find the sheet.";
+ // Copy the parameter to the current sheet
+ readSheet = SheetUtils.match(readSheet, xlsReadContext);
+ if (readSheet != null) {
+ xlsReadContext.currentSheet(readSheet);
+ xlsReadContext.xlsReadSheetHolder().setIgnoreRecord(Boolean.FALSE);
+ } else {
+ xlsReadContext.xlsReadSheetHolder().setIgnoreRecord(Boolean.TRUE);
+ }
+ // Go read the next one
+ xlsReadWorkbookHolder.setReadSheetIndex(xlsReadWorkbookHolder.getReadSheetIndex() + 1);
}
- public void init(List readSheetList, Boolean readAll) {
- this.readSheetList = readSheetList;
- this.readAll = readAll;
- }
-
- @Override
- public int getOrder() {
- return 0;
+ private void initReadSheetDataList(XlsReadWorkbookHolder xlsReadWorkbookHolder) {
+ if (xlsReadWorkbookHolder.getActualSheetDataList() != null) {
+ return;
+ }
+ BoundSheetRecord[] boundSheetRecords =
+ BoundSheetRecord.orderByBofPosition(xlsReadWorkbookHolder.getBoundSheetRecordList());
+ List readSheetDataList = new ArrayList();
+ for (int i = 0; i < boundSheetRecords.length; i++) {
+ BoundSheetRecord boundSheetRecord = boundSheetRecords[i];
+ ReadSheet readSheet = new ReadSheet(i, boundSheetRecord.getSheetname());
+ readSheetDataList.add(readSheet);
+ }
+ xlsReadWorkbookHolder.setActualSheetDataList(readSheetDataList);
+ // Just need to get the list of sheets
+ if (!xlsReadWorkbookHolder.getNeedReadSheet()) {
+ throw new ExcelAnalysisStopException("Just need to get the list of sheets.");
+ }
}
}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoolErrRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoolErrRecordHandler.java
new file mode 100644
index 0000000..8d43521
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoolErrRecordHandler.java
@@ -0,0 +1,25 @@
+package com.alibaba.excel.analysis.v03.handlers;
+
+import org.apache.poi.hssf.record.BoolErrRecord;
+import org.apache.poi.hssf.record.Record;
+
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
+import com.alibaba.excel.enums.RowTypeEnum;
+import com.alibaba.excel.metadata.CellData;
+
+/**
+ * Record handler
+ *
+ * @author Dan Zheng
+ */
+public class BoolErrRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
+
+ @Override
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ BoolErrRecord ber = (BoolErrRecord)record;
+ xlsReadContext.xlsReadSheetHolder().getCellMap().put((int)ber.getColumn(),
+ CellData.newInstance(ber.getBooleanValue(), ber.getRow(), (int)ber.getColumn()));
+ xlsReadContext.xlsReadSheetHolder().setTempRowType(RowTypeEnum.DATA);
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoundSheetRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoundSheetRecordHandler.java
new file mode 100644
index 0000000..685dcc6
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoundSheetRecordHandler.java
@@ -0,0 +1,21 @@
+package com.alibaba.excel.analysis.v03.handlers;
+
+import org.apache.poi.hssf.record.BoundSheetRecord;
+import org.apache.poi.hssf.record.Record;
+
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
+
+/**
+ * Record handler
+ *
+ * @author Dan Zheng
+ */
+public class BoundSheetRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
+
+ @Override
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ BoundSheetRecord bsr = (BoundSheetRecord)record;
+ xlsReadContext.xlsReadWorkbookHolder().getBoundSheetRecordList().add((BoundSheetRecord)record);
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordHandler.java
new file mode 100644
index 0000000..54a2d1d
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordHandler.java
@@ -0,0 +1,41 @@
+package com.alibaba.excel.analysis.v03.handlers;
+
+import java.util.LinkedHashMap;
+
+import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
+import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;
+import org.apache.poi.hssf.record.Record;
+
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
+import com.alibaba.excel.enums.RowTypeEnum;
+import com.alibaba.excel.metadata.Cell;
+import com.alibaba.excel.metadata.CellData;
+import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
+import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder;
+
+/**
+ * Record handler
+ *
+ * @author Dan Zheng
+ */
+public class DummyRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
+ @Override
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ XlsReadSheetHolder xlsReadSheetHolder = xlsReadContext.xlsReadSheetHolder();
+ if (record instanceof LastCellOfRowDummyRecord) {
+ // End of this row
+ LastCellOfRowDummyRecord lcrdr = (LastCellOfRowDummyRecord)record;
+ xlsReadSheetHolder.setRowIndex(lcrdr.getRow());
+ xlsReadContext.readRowHolder(new ReadRowHolder(lcrdr.getRow(), xlsReadSheetHolder.getTempRowType(),
+ xlsReadContext.readSheetHolder().getGlobalConfiguration(), xlsReadSheetHolder.getCellMap()));
+ xlsReadContext.analysisEventProcessor().endRow(xlsReadContext);
+ xlsReadSheetHolder.setCellMap(new LinkedHashMap());
+ xlsReadSheetHolder.setTempRowType(RowTypeEnum.EMPTY);
+ } else if (record instanceof MissingCellDummyRecord) {
+ MissingCellDummyRecord mcdr = (MissingCellDummyRecord)record;
+ xlsReadSheetHolder.getCellMap().put(mcdr.getColumn(),
+ CellData.newEmptyInstance(mcdr.getRow(), mcdr.getColumn()));
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java
new file mode 100644
index 0000000..0ca7313
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java
@@ -0,0 +1,21 @@
+package com.alibaba.excel.analysis.v03.handlers;
+
+import org.apache.poi.hssf.record.Record;
+
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
+
+/**
+ * Record handler
+ *
+ * @author Dan Zheng
+ */
+public class EofRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
+
+ @Override
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ if (xlsReadContext.readSheetHolder() != null) {
+ xlsReadContext.analysisEventProcessor().endSheet(xlsReadContext);
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java
index 0ff8f99..099b308 100644
--- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java
@@ -1,19 +1,20 @@
package com.alibaba.excel.analysis.v03.handlers;
import java.math.BigDecimal;
+import java.util.Map;
-import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.FormulaRecord;
import org.apache.poi.hssf.record.Record;
-import org.apache.poi.hssf.record.StringRecord;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.constant.BuiltinFormats;
+import com.alibaba.excel.context.xls.XlsReadContext;
import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.metadata.Cell;
import com.alibaba.excel.metadata.CellData;
/**
@@ -21,96 +22,59 @@ import com.alibaba.excel.metadata.CellData;
*
* @author Dan Zheng
*/
-public class FormulaRecordHandler extends AbstractXlsRecordHandler {
+public class FormulaRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(FormulaRecordHandler.class);
-
private static final String ERROR = "#VALUE!";
- private int nextRow;
- private int nextColumn;
- private boolean outputNextStringRecord;
- private CellData tempCellData;
- private FormatTrackingHSSFListener formatListener;
- private HSSFWorkbook stubWorkbook;
-
- public FormulaRecordHandler(HSSFWorkbook stubWorkbook, FormatTrackingHSSFListener formatListener) {
- this.stubWorkbook = stubWorkbook;
- this.formatListener = formatListener;
- }
@Override
- public boolean support(Record record) {
- return FormulaRecord.sid == record.getSid() || StringRecord.sid == record.getSid();
- }
-
- @Override
- public void processRecord(Record record) {
- if (record.getSid() == FormulaRecord.sid) {
- FormulaRecord frec = (FormulaRecord)record;
-
- this.row = frec.getRow();
- this.column = frec.getColumn();
- CellType cellType = CellType.forInt(frec.getCachedResultType());
- String formulaValue = null;
- try {
- formulaValue = HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression());
- } catch (Exception e) {
- LOGGER.warn("Get formula value error.{}", e.getMessage());
- }
- switch (cellType) {
- case STRING:
- // Formula result is a string
- // This is stored in the next record
- outputNextStringRecord = true;
- nextRow = frec.getRow();
- nextColumn = frec.getColumn();
- tempCellData = new CellData(CellDataTypeEnum.STRING);
- tempCellData.setFormula(Boolean.TRUE);
- tempCellData.setFormulaValue(formulaValue);
- break;
- case NUMERIC:
- this.cellData = new CellData(BigDecimal.valueOf(frec.getValue()));
- this.cellData.setFormula(Boolean.TRUE);
- this.cellData.setFormulaValue(formulaValue);
- break;
- case ERROR:
- this.cellData = new CellData(CellDataTypeEnum.ERROR);
- this.cellData.setStringValue(ERROR);
- this.cellData.setFormula(Boolean.TRUE);
- this.cellData.setFormulaValue(formulaValue);
- break;
- case BOOLEAN:
- this.cellData = new CellData(frec.getCachedBooleanValue());
- this.cellData.setFormula(Boolean.TRUE);
- this.cellData.setFormulaValue(formulaValue);
- break;
- default:
- this.cellData = new CellData(CellDataTypeEnum.EMPTY);
- this.cellData.setFormula(Boolean.TRUE);
- this.cellData.setFormulaValue(formulaValue);
- break;
- }
- } else if (record.getSid() == StringRecord.sid) {
- if (outputNextStringRecord) {
- // String for formula
- StringRecord srec = (StringRecord)record;
- this.cellData = tempCellData;
- this.cellData.setStringValue(srec.getString());
- this.row = nextRow;
- this.column = nextColumn;
- outputNextStringRecord = false;
- tempCellData = null;
- }
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ FormulaRecord frec = (FormulaRecord)record;
+ Map cellMap = xlsReadContext.xlsReadSheetHolder().getCellMap();
+ CellData tempCellData = new CellData();
+ tempCellData.setRowIndex(frec.getRow());
+ tempCellData.setColumnIndex((int)frec.getColumn());
+ CellType cellType = CellType.forInt(frec.getCachedResultType());
+ String formulaValue = null;
+ try {
+ formulaValue = HSSFFormulaParser.toFormulaString(xlsReadContext.xlsReadWorkbookHolder().getHssfWorkbook(),
+ frec.getParsedExpression());
+ } catch (Exception e) {
+ LOGGER.debug("Get formula value error.", e);
+ }
+ tempCellData.setFormula(Boolean.TRUE);
+ tempCellData.setFormulaValue(formulaValue);
+ switch (cellType) {
+ case STRING:
+ // Formula result is a string
+ // This is stored in the next record
+ tempCellData.setType(CellDataTypeEnum.STRING);
+ xlsReadContext.xlsReadSheetHolder().setTempCellData(tempCellData);
+ break;
+ case NUMERIC:
+ tempCellData.setType(CellDataTypeEnum.NUMBER);
+ tempCellData.setNumberValue(BigDecimal.valueOf(frec.getValue()));
+ Integer dataFormat =
+ xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatIndex(frec);
+ tempCellData.setDataFormat(dataFormat);
+ tempCellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat,
+ xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatString(frec),
+ xlsReadContext.readSheetHolder().getGlobalConfiguration().getLocale()));
+ cellMap.put((int)frec.getColumn(), tempCellData);
+ break;
+ case ERROR:
+ tempCellData.setType(CellDataTypeEnum.ERROR);
+ tempCellData.setStringValue(ERROR);
+ cellMap.put((int)frec.getColumn(), tempCellData);
+ break;
+ case BOOLEAN:
+ tempCellData.setType(CellDataTypeEnum.BOOLEAN);
+ tempCellData.setBooleanValue(frec.getCachedBooleanValue());
+ cellMap.put((int)frec.getColumn(), tempCellData);
+ break;
+ default:
+ tempCellData.setType(CellDataTypeEnum.EMPTY);
+ cellMap.put((int)frec.getColumn(), tempCellData);
+ break;
}
- }
-
- @Override
- public void init() {
- this.nextRow = 0;
- this.nextColumn = 0;
- }
-
- @Override
- public int getOrder() {
- return 0;
}
}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/HyperlinkRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/HyperlinkRecordHandler.java
new file mode 100644
index 0000000..99c3a80
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/HyperlinkRecordHandler.java
@@ -0,0 +1,30 @@
+package com.alibaba.excel.analysis.v03.handlers;
+
+import org.apache.poi.hssf.record.HyperlinkRecord;
+import org.apache.poi.hssf.record.Record;
+
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
+import com.alibaba.excel.enums.CellExtraTypeEnum;
+import com.alibaba.excel.metadata.CellExtra;
+
+/**
+ * Record handler
+ *
+ * @author Dan Zheng
+ */
+public class HyperlinkRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
+ @Override
+ public boolean support(XlsReadContext xlsReadContext, Record record) {
+ return xlsReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.HYPERLINK);
+ }
+
+ @Override
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ HyperlinkRecord hr = (HyperlinkRecord)record;
+ CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.HYPERLINK, hr.getAddress(), hr.getFirstRow(),
+ hr.getLastRow(), hr.getFirstColumn(), hr.getLastColumn());
+ xlsReadContext.xlsReadSheetHolder().setCellExtra(cellExtra);
+ xlsReadContext.analysisEventProcessor().extra(xlsReadContext);
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java
index 6837ebd..b95812e 100644
--- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java
@@ -3,40 +3,20 @@ package com.alibaba.excel.analysis.v03.handlers;
import org.apache.poi.hssf.record.IndexRecord;
import org.apache.poi.hssf.record.Record;
-import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
-import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
/**
* Record handler
*
* @author Jiaju Zhuang
*/
-public class IndexRecordHandler extends AbstractXlsRecordHandler {
-
- private AnalysisContext context;
-
- public IndexRecordHandler(AnalysisContext context) {
- this.context = context;
- }
-
- @Override
- public boolean support(Record record) {
- return record instanceof IndexRecord;
- }
-
- @Override
- public void init() {}
-
+public class IndexRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
@Override
- public void processRecord(Record record) {
- if (context.readSheetHolder() == null) {
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ if (xlsReadContext.readSheetHolder() == null) {
return;
}
- context.readSheetHolder().setApproximateTotalRowNumber(((IndexRecord)record).getLastRowAdd1());
- }
-
- @Override
- public int getOrder() {
- return 1;
+ xlsReadContext.readSheetHolder().setApproximateTotalRowNumber(((IndexRecord)record).getLastRowAdd1());
}
}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java
index 35732c1..4f63ab0 100644
--- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java
@@ -3,7 +3,9 @@ package com.alibaba.excel.analysis.v03.handlers;
import org.apache.poi.hssf.record.LabelRecord;
import org.apache.poi.hssf.record.Record;
-import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
+import com.alibaba.excel.enums.RowTypeEnum;
import com.alibaba.excel.metadata.CellData;
/**
@@ -11,27 +13,16 @@ import com.alibaba.excel.metadata.CellData;
*
* @author Dan Zheng
*/
-public class LabelRecordHandler extends AbstractXlsRecordHandler {
+public class LabelRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
@Override
- public boolean support(Record record) {
- return LabelRecord.sid == record.getSid();
- }
-
- @Override
- public void processRecord(Record record) {
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
LabelRecord lrec = (LabelRecord)record;
- this.row = lrec.getRow();
- this.column = lrec.getColumn();
- this.cellData = new CellData(lrec.getValue());
- }
-
- @Override
- public void init() {
-
- }
-
- @Override
- public int getOrder() {
- return 0;
+ String data = lrec.getValue();
+ if (data != null && xlsReadContext.currentReadHolder().globalConfiguration().getAutoTrim()) {
+ data = data.trim();
+ }
+ xlsReadContext.xlsReadSheetHolder().getCellMap().put((int)lrec.getColumn(),
+ CellData.newInstance(data, lrec.getRow(), (int)lrec.getColumn()));
+ xlsReadContext.xlsReadSheetHolder().setTempRowType(RowTypeEnum.DATA);
}
}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSstRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSstRecordHandler.java
new file mode 100644
index 0000000..7fb5cd0
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSstRecordHandler.java
@@ -0,0 +1,42 @@
+package com.alibaba.excel.analysis.v03.handlers;
+
+import java.util.Map;
+
+import org.apache.poi.hssf.record.LabelSSTRecord;
+import org.apache.poi.hssf.record.Record;
+
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.cache.ReadCache;
+import com.alibaba.excel.context.xls.XlsReadContext;
+import com.alibaba.excel.enums.RowTypeEnum;
+import com.alibaba.excel.metadata.Cell;
+import com.alibaba.excel.metadata.CellData;
+
+/**
+ * Record handler
+ *
+ * @author Dan Zheng
+ */
+public class LabelSstRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
+
+ @Override
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ LabelSSTRecord lsrec = (LabelSSTRecord)record;
+ ReadCache readCache = xlsReadContext.readWorkbookHolder().getReadCache();
+ Map cellMap = xlsReadContext.xlsReadSheetHolder().getCellMap();
+ if (readCache == null) {
+ cellMap.put((int)lsrec.getColumn(), CellData.newEmptyInstance(lsrec.getRow(), (int)lsrec.getColumn()));
+ return;
+ }
+ String data = readCache.get(lsrec.getSSTIndex());
+ if (data == null) {
+ cellMap.put((int)lsrec.getColumn(), CellData.newEmptyInstance(lsrec.getRow(), (int)lsrec.getColumn()));
+ return;
+ }
+ if (xlsReadContext.currentReadHolder().globalConfiguration().getAutoTrim()) {
+ data = data.trim();
+ }
+ cellMap.put((int)lsrec.getColumn(), CellData.newInstance(data, lsrec.getRow(), (int)lsrec.getColumn()));
+ xlsReadContext.xlsReadSheetHolder().setTempRowType(RowTypeEnum.DATA);
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/MergeCellsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/MergeCellsRecordHandler.java
new file mode 100644
index 0000000..f9bf472
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/MergeCellsRecordHandler.java
@@ -0,0 +1,35 @@
+package com.alibaba.excel.analysis.v03.handlers;
+
+import org.apache.poi.hssf.record.MergeCellsRecord;
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.ss.util.CellRangeAddress;
+
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
+import com.alibaba.excel.enums.CellExtraTypeEnum;
+import com.alibaba.excel.metadata.CellExtra;
+
+/**
+ * Record handler
+ *
+ * @author Dan Zheng
+ */
+public class MergeCellsRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
+
+ @Override
+ public boolean support(XlsReadContext xlsReadContext, Record record) {
+ return xlsReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.MERGE);
+ }
+
+ @Override
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ MergeCellsRecord mcr = (MergeCellsRecord)record;
+ for (int i = 0; i < mcr.getNumAreas(); i++) {
+ CellRangeAddress cellRangeAddress = mcr.getAreaAt(i);
+ CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.MERGE, null, cellRangeAddress.getFirstRow(),
+ cellRangeAddress.getLastRow(), cellRangeAddress.getFirstColumn(), cellRangeAddress.getLastColumn());
+ xlsReadContext.xlsReadSheetHolder().setCellExtra(cellExtra);
+ xlsReadContext.analysisEventProcessor().extra(xlsReadContext);
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java
deleted file mode 100644
index c879504..0000000
--- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.alibaba.excel.analysis.v03.handlers;
-
-import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;
-import org.apache.poi.hssf.record.Record;
-
-import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
-import com.alibaba.excel.enums.CellDataTypeEnum;
-import com.alibaba.excel.metadata.CellData;
-
-/**
- * Record handler
- *
- * @author Dan Zheng
- */
-public class MissingCellDummyRecordHandler extends AbstractXlsRecordHandler {
- @Override
- public boolean support(Record record) {
- return record instanceof MissingCellDummyRecord;
- }
-
- @Override
- public void init() {
-
- }
-
- @Override
- public void processRecord(Record record) {
- MissingCellDummyRecord mcdr = (MissingCellDummyRecord)record;
- this.row = mcdr.getRow();
- this.column = mcdr.getColumn();
- this.cellData = new CellData(CellDataTypeEnum.EMPTY);
- }
-
- @Override
- public int getOrder() {
- return 1;
- }
-}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java
index 9ab800c..6b6d803 100644
--- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java
@@ -3,36 +3,29 @@ package com.alibaba.excel.analysis.v03.handlers;
import org.apache.poi.hssf.record.NoteRecord;
import org.apache.poi.hssf.record.Record;
-import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
-import com.alibaba.excel.enums.CellDataTypeEnum;
-import com.alibaba.excel.metadata.CellData;
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
+import com.alibaba.excel.enums.CellExtraTypeEnum;
+import com.alibaba.excel.metadata.CellExtra;
/**
* Record handler
*
* @author Dan Zheng
*/
-public class NoteRecordHandler extends AbstractXlsRecordHandler {
- @Override
- public boolean support(Record record) {
- return NoteRecord.sid == record.getSid();
- }
-
- @Override
- public void processRecord(Record record) {
- NoteRecord nrec = (NoteRecord)record;
- this.row = nrec.getRow();
- this.column = nrec.getColumn();
- this.cellData = new CellData(CellDataTypeEnum.EMPTY);
- }
+public class NoteRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
@Override
- public void init() {
-
+ public boolean support(XlsReadContext xlsReadContext, Record record) {
+ return xlsReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.COMMENT);
}
@Override
- public int getOrder() {
- return 0;
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ NoteRecord nr = (NoteRecord)record;
+ String text = xlsReadContext.xlsReadSheetHolder().getObjectCacheMap().get(nr.getShapeId());
+ CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.COMMENT, text, nr.getRow(), nr.getColumn());
+ xlsReadContext.xlsReadSheetHolder().setCellExtra(cellExtra);
+ xlsReadContext.analysisEventProcessor().extra(xlsReadContext);
}
}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java
index 75c3128..5060809 100644
--- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java
@@ -2,11 +2,13 @@ package com.alibaba.excel.analysis.v03.handlers;
import java.math.BigDecimal;
-import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.Record;
-import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.constant.BuiltinFormats;
+import com.alibaba.excel.context.xls.XlsReadContext;
+import com.alibaba.excel.enums.RowTypeEnum;
import com.alibaba.excel.metadata.CellData;
/**
@@ -14,35 +16,18 @@ import com.alibaba.excel.metadata.CellData;
*
* @author Dan Zheng
*/
-public class NumberRecordHandler extends AbstractXlsRecordHandler {
- private FormatTrackingHSSFListener formatListener;
-
- public NumberRecordHandler(FormatTrackingHSSFListener formatListener) {
- this.formatListener = formatListener;
- }
-
- @Override
- public boolean support(Record record) {
- return NumberRecord.sid == record.getSid();
- }
-
- @Override
- public void processRecord(Record record) {
- NumberRecord numrec = (NumberRecord)record;
- this.row = numrec.getRow();
- this.column = numrec.getColumn();
- this.cellData = new CellData(BigDecimal.valueOf(numrec.getValue()));
- this.cellData.setDataFormat(formatListener.getFormatIndex(numrec));
- this.cellData.setDataFormatString(formatListener.getFormatString(numrec));
- }
-
- @Override
- public void init() {
-
- }
+public class NumberRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
@Override
- public int getOrder() {
- return 0;
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ NumberRecord nr = (NumberRecord)record;
+ CellData cellData = CellData.newInstance(BigDecimal.valueOf(nr.getValue()), nr.getRow(), (int)nr.getColumn());
+ Integer dataFormat = xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatIndex(nr);
+ cellData.setDataFormat(dataFormat);
+ cellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat,
+ xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatString(nr),
+ xlsReadContext.readSheetHolder().getGlobalConfiguration().getLocale()));
+ xlsReadContext.xlsReadSheetHolder().getCellMap().put((int)nr.getColumn(), cellData);
+ xlsReadContext.xlsReadSheetHolder().setTempRowType(RowTypeEnum.DATA);
}
}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/ObjRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/ObjRecordHandler.java
new file mode 100644
index 0000000..97bcd20
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/ObjRecordHandler.java
@@ -0,0 +1,30 @@
+package com.alibaba.excel.analysis.v03.handlers;
+
+import org.apache.poi.hssf.record.CommonObjectDataSubRecord;
+import org.apache.poi.hssf.record.ObjRecord;
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.SubRecord;
+
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
+
+/**
+ * Record handler
+ *
+ * @author Jiaju Zhuang
+ */
+public class ObjRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
+ @Override
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ ObjRecord or = (ObjRecord)record;
+ for (SubRecord subRecord : or.getSubRecords()) {
+ if (subRecord instanceof CommonObjectDataSubRecord) {
+ CommonObjectDataSubRecord codsr = (CommonObjectDataSubRecord)subRecord;
+ if (CommonObjectDataSubRecord.OBJECT_TYPE_COMMENT == codsr.getObjectType()) {
+ xlsReadContext.xlsReadSheetHolder().setTempObjectIndex(codsr.getObjectId());
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java
index 140fb72..d8317b3 100644
--- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java
@@ -3,8 +3,8 @@ package com.alibaba.excel.analysis.v03.handlers;
import org.apache.poi.hssf.record.RKRecord;
import org.apache.poi.hssf.record.Record;
-import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
-import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
import com.alibaba.excel.metadata.CellData;
/**
@@ -12,28 +12,12 @@ import com.alibaba.excel.metadata.CellData;
*
* @author Dan Zheng
*/
-public class RkRecordHandler extends AbstractXlsRecordHandler {
- @Override
- public boolean support(Record record) {
- return RKRecord.sid == record.getSid();
- }
-
- @Override
- public void processRecord(Record record) {
- RKRecord rkrec = (RKRecord)record;
-
- this.row = rkrec.getRow();
- this.row = rkrec.getColumn();
- this.cellData = new CellData(CellDataTypeEnum.EMPTY);
- }
-
- @Override
- public void init() {
-
- }
+public class RkRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
@Override
- public int getOrder() {
- return 0;
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ RKRecord re = (RKRecord)record;
+ xlsReadContext.xlsReadSheetHolder().getCellMap().put((int)re.getColumn(),
+ CellData.newEmptyInstance(re.getRow(), (int)re.getColumn()));
}
}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java
index 5c1c8ae..35727b6 100644
--- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java
@@ -1,49 +1,20 @@
package com.alibaba.excel.analysis.v03.handlers;
-import org.apache.poi.hssf.record.LabelSSTRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.SSTRecord;
-import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
-import com.alibaba.excel.enums.CellDataTypeEnum;
-import com.alibaba.excel.metadata.CellData;
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.cache.XlsCache;
+import com.alibaba.excel.context.xls.XlsReadContext;
/**
* Record handler
*
* @author Dan Zheng
*/
-public class SstRecordHandler extends AbstractXlsRecordHandler {
- private SSTRecord sstRecord;
-
- @Override
- public boolean support(Record record) {
- return SSTRecord.sid == record.getSid() || LabelSSTRecord.sid == record.getSid();
- }
-
- @Override
- public void processRecord(Record record) {
- if (record.getSid() == SSTRecord.sid) {
- sstRecord = (SSTRecord)record;
- } else if (record.getSid() == LabelSSTRecord.sid) {
- LabelSSTRecord lsrec = (LabelSSTRecord)record;
- this.row = lsrec.getRow();
- this.column = lsrec.getColumn();
- if (sstRecord == null) {
- this.cellData = new CellData(CellDataTypeEnum.EMPTY);
- } else {
- this.cellData = new CellData(sstRecord.getString(lsrec.getSSTIndex()).toString());
- }
- }
- }
-
- @Override
- public void init() {
-
- }
-
+public class SstRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
@Override
- public int getOrder() {
- return 0;
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ xlsReadContext.readWorkbookHolder().setReadCache(new XlsCache((SSTRecord)record));
}
}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java
new file mode 100644
index 0000000..3b95cfd
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java
@@ -0,0 +1,35 @@
+package com.alibaba.excel.analysis.v03.handlers;
+
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.StringRecord;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
+import com.alibaba.excel.metadata.CellData;
+import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder;
+
+/**
+ * Record handler
+ *
+ * @author Dan Zheng
+ */
+public class StringRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
+ private static final Logger LOGGER = LoggerFactory.getLogger(StringRecordHandler.class);
+
+ @Override
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ // String for formula
+ StringRecord srec = (StringRecord)record;
+ XlsReadSheetHolder xlsReadSheetHolder = xlsReadContext.xlsReadSheetHolder();
+ CellData tempCellData = xlsReadSheetHolder.getTempCellData();
+ if (tempCellData == null) {
+ LOGGER.warn("String type formula but no value found.");
+ return;
+ }
+ tempCellData.setStringValue(srec.getString());
+ xlsReadSheetHolder.getCellMap().put(tempCellData.getColumnIndex(), tempCellData);
+ xlsReadSheetHolder.setTempCellData(null);
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java
new file mode 100644
index 0000000..949498f
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java
@@ -0,0 +1,38 @@
+package com.alibaba.excel.analysis.v03.handlers;
+
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.TextObjectRecord;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
+import com.alibaba.excel.context.xls.XlsReadContext;
+import com.alibaba.excel.enums.CellExtraTypeEnum;
+import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder;
+
+/**
+ * Record handler
+ *
+ * @author Jiaju Zhuang
+ */
+public class TextObjectRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
+ private static final Logger LOGGER = LoggerFactory.getLogger(TextObjectRecordHandler.class);
+
+ @Override
+ public boolean support(XlsReadContext xlsReadContext, Record record) {
+ return xlsReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.COMMENT);
+ }
+
+ @Override
+ public void processRecord(XlsReadContext xlsReadContext, Record record) {
+ TextObjectRecord tor = (TextObjectRecord)record;
+ XlsReadSheetHolder xlsReadSheetHolder = xlsReadContext.xlsReadSheetHolder();
+ Integer tempObjectIndex = xlsReadSheetHolder.getTempObjectIndex();
+ if (tempObjectIndex == null) {
+ LOGGER.debug("tempObjectIndex is null.");
+ return;
+ }
+ xlsReadSheetHolder.getObjectCacheMap().put(tempObjectIndex, tor.getStr().getString());
+ xlsReadSheetHolder.setTempObjectIndex(null);
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java
deleted file mode 100644
index a4db7f4..0000000
--- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.alibaba.excel.analysis.v07;
-
-import org.xml.sax.Attributes;
-
-/**
- * Cell handler
- *
- * @author Dan Zheng
- */
-public interface XlsxCellHandler {
- /**
- * Which tags are supported
- *
- * @param name
- * Tag name
- * @return Support parsing or not
- */
- boolean support(String name);
-
- /**
- * Start handle
- *
- * @param name
- * Tag name
- * @param attributes
- * Tag attributes
- */
- void startHandle(String name, Attributes attributes);
-
- /**
- * End handle
- *
- * @param name
- * Tag name
- */
- void endHandle(String name);
-}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java
deleted file mode 100644
index 82f7d2c..0000000
--- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.alibaba.excel.analysis.v07;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.poi.xssf.model.StylesTable;
-
-import com.alibaba.excel.analysis.v07.handlers.CountRowCellHandler;
-import com.alibaba.excel.analysis.v07.handlers.DefaultCellHandler;
-import com.alibaba.excel.analysis.v07.handlers.ProcessResultCellHandler;
-import com.alibaba.excel.context.AnalysisContext;
-
-/**
- * Build handler
- *
- * @author Dan Zheng
- */
-public class XlsxHandlerFactory {
- public static List buildCellHandlers(AnalysisContext analysisContext, StylesTable stylesTable) {
- List result = new ArrayList();
- result.add(new CountRowCellHandler(analysisContext));
- DefaultCellHandler defaultCellHandler = new DefaultCellHandler(analysisContext, stylesTable);
- result.add(defaultCellHandler);
- result.add(new ProcessResultCellHandler(analysisContext, defaultCellHandler));
- return result;
- }
-}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java
deleted file mode 100644
index ececb47..0000000
--- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.alibaba.excel.analysis.v07;
-
-import java.util.List;
-
-import org.apache.poi.xssf.model.StylesTable;
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
-import com.alibaba.excel.context.AnalysisContext;
-
-/**
- *
- * @author jipengfei
- */
-public class XlsxRowHandler extends DefaultHandler {
-
- private List cellHandlers;
- private XlsxRowResultHolder rowResultHolder;
-
- public XlsxRowHandler(AnalysisContext analysisContext, StylesTable stylesTable) {
- this.cellHandlers = XlsxHandlerFactory.buildCellHandlers(analysisContext, stylesTable);
- for (XlsxCellHandler cellHandler : cellHandlers) {
- if (cellHandler instanceof XlsxRowResultHolder) {
- this.rowResultHolder = (XlsxRowResultHolder)cellHandler;
- break;
- }
- }
- }
-
- @Override
- public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
- for (XlsxCellHandler cellHandler : cellHandlers) {
- if (cellHandler.support(name)) {
- cellHandler.startHandle(name, attributes);
- }
- }
- }
-
- @Override
- public void endElement(String uri, String localName, String name) throws SAXException {
- for (XlsxCellHandler cellHandler : cellHandlers) {
- if (cellHandler.support(name)) {
- cellHandler.endHandle(name);
- }
- }
- }
-
- @Override
- public void characters(char[] ch, int start, int length) throws SAXException {
- if (rowResultHolder != null) {
- rowResultHolder.appendCurrentCellValue(ch, start, length);
- }
- }
-}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java
deleted file mode 100644
index d13da73..0000000
--- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.alibaba.excel.analysis.v07;
-
-import java.util.Map;
-
-import com.alibaba.excel.metadata.CellData;
-
-/**
- * Result holder
- *
- * @author jipengfei
- */
-public interface XlsxRowResultHolder {
- /**
- * Clear Result
- */
- void clearResult();
-
- /**
- * Append current 'cellValue'
- *
- * @param ch
- * @param start
- * @param length
- */
- void appendCurrentCellValue(char[] ch, int start, int length);
-
- /**
- * Get row content
- *
- * @return
- */
- Map getCurRowContent();
-}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java
index 2862be2..a0a9af0 100644
--- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java
+++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java
@@ -15,8 +15,10 @@ import javax.xml.parsers.SAXParserFactory;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.ss.util.CellAddress;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
-import org.apache.poi.xssf.model.StylesTable;
+import org.apache.poi.xssf.model.CommentsTable;
+import org.apache.poi.xssf.usermodel.XSSFComment;
import org.apache.poi.xssf.usermodel.XSSFRelation;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr;
@@ -26,37 +28,40 @@ import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import com.alibaba.excel.analysis.ExcelReadExecutor;
+import com.alibaba.excel.analysis.v07.handlers.sax.SharedStringsTableHandler;
+import com.alibaba.excel.analysis.v07.handlers.sax.XlsxRowHandler;
import com.alibaba.excel.cache.ReadCache;
-import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.context.xlsx.XlsxReadContext;
+import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.exception.ExcelAnalysisException;
+import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.metadata.ReadSheet;
-import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
+import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.util.SheetUtils;
import com.alibaba.excel.util.StringUtils;
/**
- *
* @author jipengfei
*/
public class XlsxSaxAnalyser implements ExcelReadExecutor {
- private AnalysisContext analysisContext;
+ private XlsxReadContext xlsxReadContext;
private List sheetList;
private Map sheetMap;
/**
- * Current style information
+ * excel comments key: sheetNo value: CommentsTable
*/
- private StylesTable stylesTable;
+ private Map commentsTableMap;
- public XlsxSaxAnalyser(AnalysisContext analysisContext, InputStream decryptedStream) throws Exception {
- this.analysisContext = analysisContext;
+ public XlsxSaxAnalyser(XlsxReadContext xlsxReadContext, InputStream decryptedStream) throws Exception {
+ this.xlsxReadContext = xlsxReadContext;
// Initialize cache
- ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder();
+ XlsxReadWorkbookHolder xlsxReadWorkbookHolder = xlsxReadContext.xlsxReadWorkbookHolder();
- OPCPackage pkg = readOpcPackage(readWorkbookHolder, decryptedStream);
- readWorkbookHolder.setOpcPackage(pkg);
+ OPCPackage pkg = readOpcPackage(xlsxReadWorkbookHolder, decryptedStream);
+ xlsxReadWorkbookHolder.setOpcPackage(pkg);
ArrayList packageParts = pkg.getPartsByContentType(XSSFRelation.SHARED_STRINGS.getContentType());
@@ -64,18 +69,19 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
PackagePart sharedStringsTablePackagePart = packageParts.get(0);
// Specify default cache
- defaultReadCache(readWorkbookHolder, sharedStringsTablePackagePart);
+ defaultReadCache(xlsxReadWorkbookHolder, sharedStringsTablePackagePart);
// Analysis sharedStringsTable.xml
- analysisSharedStringsTable(sharedStringsTablePackagePart.getInputStream(), readWorkbookHolder);
+ analysisSharedStringsTable(sharedStringsTablePackagePart.getInputStream(), xlsxReadWorkbookHolder);
}
XSSFReader xssfReader = new XSSFReader(pkg);
- analysisUse1904WindowDate(xssfReader, readWorkbookHolder);
+ analysisUse1904WindowDate(xssfReader, xlsxReadWorkbookHolder);
- stylesTable = xssfReader.getStylesTable();
+ xlsxReadWorkbookHolder.setStylesTable(xssfReader.getStylesTable());
sheetList = new ArrayList();
sheetMap = new HashMap();
+ commentsTableMap = new HashMap();
XSSFReader.SheetIterator ite = (XSSFReader.SheetIterator)xssfReader.getSheetsData();
int index = 0;
if (!ite.hasNext()) {
@@ -85,19 +91,26 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
InputStream inputStream = ite.next();
sheetList.add(new ReadSheet(index, ite.getSheetName()));
sheetMap.put(index, inputStream);
+ if (xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.COMMENT)) {
+ CommentsTable commentsTable = ite.getSheetComments();
+ if (null != commentsTable) {
+ commentsTableMap.put(index, commentsTable);
+ }
+ }
index++;
}
}
- private void defaultReadCache(ReadWorkbookHolder readWorkbookHolder, PackagePart sharedStringsTablePackagePart) {
- ReadCache readCache = readWorkbookHolder.getReadCacheSelector().readCache(sharedStringsTablePackagePart);
- readWorkbookHolder.setReadCache(readCache);
- readCache.init(analysisContext);
+ private void defaultReadCache(XlsxReadWorkbookHolder xlsxReadWorkbookHolder,
+ PackagePart sharedStringsTablePackagePart) {
+ ReadCache readCache = xlsxReadWorkbookHolder.getReadCacheSelector().readCache(sharedStringsTablePackagePart);
+ xlsxReadWorkbookHolder.setReadCache(readCache);
+ readCache.init(xlsxReadContext);
}
- private void analysisUse1904WindowDate(XSSFReader xssfReader, ReadWorkbookHolder readWorkbookHolder)
+ private void analysisUse1904WindowDate(XSSFReader xssfReader, XlsxReadWorkbookHolder xlsxReadWorkbookHolder)
throws Exception {
- if (readWorkbookHolder.globalConfiguration().getUse1904windowing() != null) {
+ if (xlsxReadWorkbookHolder.globalConfiguration().getUse1904windowing() != null) {
return;
}
InputStream workbookXml = xssfReader.getWorkbookData();
@@ -105,38 +118,38 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
CTWorkbook wb = ctWorkbook.getWorkbook();
CTWorkbookPr prefix = wb.getWorkbookPr();
if (prefix != null && prefix.getDate1904()) {
- readWorkbookHolder.getGlobalConfiguration().setUse1904windowing(Boolean.TRUE);
+ xlsxReadWorkbookHolder.getGlobalConfiguration().setUse1904windowing(Boolean.TRUE);
} else {
- readWorkbookHolder.getGlobalConfiguration().setUse1904windowing(Boolean.FALSE);
+ xlsxReadWorkbookHolder.getGlobalConfiguration().setUse1904windowing(Boolean.FALSE);
}
}
private void analysisSharedStringsTable(InputStream sharedStringsTableInputStream,
- ReadWorkbookHolder readWorkbookHolder) throws Exception {
- ContentHandler handler = new SharedStringsTableHandler(readWorkbookHolder.getReadCache());
+ XlsxReadWorkbookHolder xlsxReadWorkbookHolder) throws Exception {
+ ContentHandler handler = new SharedStringsTableHandler(xlsxReadWorkbookHolder.getReadCache());
parseXmlSource(sharedStringsTableInputStream, handler);
- readWorkbookHolder.getReadCache().putFinished();
+ xlsxReadWorkbookHolder.getReadCache().putFinished();
}
- private OPCPackage readOpcPackage(ReadWorkbookHolder readWorkbookHolder, InputStream decryptedStream)
+ private OPCPackage readOpcPackage(XlsxReadWorkbookHolder xlsxReadWorkbookHolder, InputStream decryptedStream)
throws Exception {
- if (decryptedStream == null && readWorkbookHolder.getFile() != null) {
- return OPCPackage.open(readWorkbookHolder.getFile());
+ if (decryptedStream == null && xlsxReadWorkbookHolder.getFile() != null) {
+ return OPCPackage.open(xlsxReadWorkbookHolder.getFile());
}
- if (readWorkbookHolder.getMandatoryUseInputStream()) {
+ if (xlsxReadWorkbookHolder.getMandatoryUseInputStream()) {
if (decryptedStream != null) {
return OPCPackage.open(decryptedStream);
} else {
- return OPCPackage.open(readWorkbookHolder.getInputStream());
+ return OPCPackage.open(xlsxReadWorkbookHolder.getInputStream());
}
}
File readTempFile = FileUtils.createCacheTmpFile();
- readWorkbookHolder.setTempFile(readTempFile);
+ xlsxReadWorkbookHolder.setTempFile(readTempFile);
File tempFile = new File(readTempFile.getPath(), UUID.randomUUID().toString() + ".xlsx");
if (decryptedStream != null) {
FileUtils.writeToFile(tempFile, decryptedStream);
} else {
- FileUtils.writeToFile(tempFile, readWorkbookHolder.getInputStream());
+ FileUtils.writeToFile(tempFile, xlsxReadWorkbookHolder.getInputStream());
}
return OPCPackage.open(tempFile, PackageAccess.READ);
}
@@ -150,7 +163,7 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
InputSource inputSource = new InputSource(inputStream);
try {
SAXParserFactory saxFactory;
- String xlsxSAXParserFactoryName = analysisContext.readWorkbookHolder().getXlsxSAXParserFactoryName();
+ String xlsxSAXParserFactoryName = xlsxReadContext.xlsxReadWorkbookHolder().getSaxParserFactoryName();
if (StringUtils.isEmpty(xlsxSAXParserFactoryName)) {
saxFactory = SAXParserFactory.newInstance();
} else {
@@ -180,16 +193,34 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
}
@Override
- public void execute(List readSheetList, Boolean readAll) {
+ public void execute() {
for (ReadSheet readSheet : sheetList) {
- readSheet = SheetUtils.match(readSheet, readSheetList, readAll,
- analysisContext.readWorkbookHolder().getGlobalConfiguration());
+ readSheet = SheetUtils.match(readSheet, xlsxReadContext);
if (readSheet != null) {
- analysisContext.currentSheet(readSheet);
- parseXmlSource(sheetMap.get(readSheet.getSheetNo()), new XlsxRowHandler(analysisContext, stylesTable));
+ xlsxReadContext.currentSheet(readSheet);
+ parseXmlSource(sheetMap.get(readSheet.getSheetNo()), new XlsxRowHandler(xlsxReadContext));
+ // Read comments
+ readComments(readSheet);
// The last sheet is read
- analysisContext.readSheetHolder().notifyAfterAllAnalysed(analysisContext);
+ xlsxReadContext.analysisEventProcessor().endSheet(xlsxReadContext);
}
}
}
+
+ private void readComments(ReadSheet readSheet) {
+ if (!xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.COMMENT)) {
+ return;
+ }
+ CommentsTable commentsTable = commentsTableMap.get(readSheet.getSheetNo());
+ if (commentsTable == null) {
+ return;
+ }
+ Map cellComments = commentsTable.getCellComments();
+ for (XSSFComment xssfComment : cellComments.values()) {
+ CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.COMMENT, xssfComment.getString().toString(),
+ xssfComment.getRow(), xssfComment.getColumn());
+ xlsxReadContext.readSheetHolder().setCellExtra(cellExtra);
+ xlsxReadContext.analysisEventProcessor().extra(xlsxReadContext);
+ }
+ }
}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java
new file mode 100644
index 0000000..3521e46
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java
@@ -0,0 +1,66 @@
+package com.alibaba.excel.analysis.v07.handlers;
+
+import java.math.BigDecimal;
+
+import com.alibaba.excel.context.xlsx.XlsxReadContext;
+import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.metadata.CellData;
+import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder;
+import com.alibaba.excel.util.BooleanUtils;
+
+/**
+ * Cell Value Handler
+ *
+ * @author jipengfei
+ */
+public abstract class AbstractCellValueTagHandler extends AbstractXlsxTagHandler {
+
+ @Override
+ public void endElement(XlsxReadContext xlsxReadContext, String name) {
+ XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder();
+ CellData tempCellData = xlsxReadSheetHolder.getTempCellData();
+ StringBuilder tempData = xlsxReadSheetHolder.getTempData();
+ CellDataTypeEnum oldType = tempCellData.getType();
+ switch (oldType) {
+ case DIRECT_STRING:
+ case STRING:
+ case ERROR:
+ tempCellData.setStringValue(tempData.toString());
+ break;
+ case BOOLEAN:
+ tempCellData.setBooleanValue(BooleanUtils.valueOf(tempData.toString()));
+ break;
+ case NUMBER:
+ case EMPTY:
+ tempCellData.setType(CellDataTypeEnum.NUMBER);
+ tempCellData.setNumberValue(new BigDecimal(tempData.toString()));
+ break;
+ default:
+ throw new IllegalStateException("Cannot set values now");
+ }
+
+ // set string value
+ setStringValue(xlsxReadContext);
+
+ if (tempCellData.getStringValue() != null
+ && xlsxReadContext.currentReadHolder().globalConfiguration().getAutoTrim()) {
+ tempCellData.setStringValue(tempCellData.getStringValue());
+ }
+
+ tempCellData.checkEmpty();
+ xlsxReadSheetHolder.getCellMap().put(xlsxReadSheetHolder.getColumnIndex(), tempCellData);
+ }
+
+ @Override
+ public void characters(XlsxReadContext xlsxReadContext, char[] ch, int start, int length) {
+ xlsxReadContext.xlsxReadSheetHolder().getTempData().append(ch, start, length);
+ }
+
+ /**
+ * Set string value.
+ *
+ * @param xlsxReadContext
+ */
+ protected abstract void setStringValue(XlsxReadContext xlsxReadContext);
+
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractXlsxTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractXlsxTagHandler.java
new file mode 100644
index 0000000..169fe00
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractXlsxTagHandler.java
@@ -0,0 +1,32 @@
+package com.alibaba.excel.analysis.v07.handlers;
+
+import org.xml.sax.Attributes;
+
+import com.alibaba.excel.context.xlsx.XlsxReadContext;
+
+/**
+ * Abstract tag handler
+ *
+ * @author Jiaju Zhuang
+ */
+public abstract class AbstractXlsxTagHandler implements XlsxTagHandler {
+ @Override
+ public boolean support(XlsxReadContext xlsxReadContext) {
+ return true;
+ }
+
+ @Override
+ public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) {
+
+ }
+
+ @Override
+ public void endElement(XlsxReadContext xlsxReadContext, String name) {
+
+ }
+
+ @Override
+ public void characters(XlsxReadContext xlsxReadContext, char[] ch, int start, int length) {
+
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellFormulaTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellFormulaTagHandler.java
new file mode 100644
index 0000000..e153a3b
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellFormulaTagHandler.java
@@ -0,0 +1,32 @@
+package com.alibaba.excel.analysis.v07.handlers;
+
+import org.xml.sax.Attributes;
+
+import com.alibaba.excel.context.xlsx.XlsxReadContext;
+import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder;
+
+/**
+ * Cell Handler
+ *
+ * @author jipengfei
+ */
+public class CellFormulaTagHandler extends AbstractXlsxTagHandler {
+
+ @Override
+ public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) {
+ XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder();
+ xlsxReadSheetHolder.getTempCellData().setFormula(Boolean.TRUE);
+ xlsxReadSheetHolder.setTempFormula(new StringBuilder());
+ }
+
+ @Override
+ public void endElement(XlsxReadContext xlsxReadContext, String name) {
+ XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder();
+ xlsxReadSheetHolder.getTempCellData().setFormulaValue(xlsxReadSheetHolder.getTempFormula().toString());
+ }
+
+ @Override
+ public void characters(XlsxReadContext xlsxReadContext, char[] ch, int start, int length) {
+ xlsxReadContext.xlsxReadSheetHolder().getTempFormula().append(ch, start, length);
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellInlineStringValueTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellInlineStringValueTagHandler.java
new file mode 100644
index 0000000..277348a
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellInlineStringValueTagHandler.java
@@ -0,0 +1,23 @@
+package com.alibaba.excel.analysis.v07.handlers;
+
+import org.apache.poi.xssf.usermodel.XSSFRichTextString;
+
+import com.alibaba.excel.context.xlsx.XlsxReadContext;
+import com.alibaba.excel.metadata.CellData;
+
+/**
+ * Cell inline string value handler
+ *
+ * @author jipengfei
+ */
+public class CellInlineStringValueTagHandler extends AbstractCellValueTagHandler {
+
+ @Override
+ protected void setStringValue(XlsxReadContext xlsxReadContext) {
+ // This is a special form of string
+ CellData tempCellData = xlsxReadContext.xlsxReadSheetHolder().getTempCellData();
+ XSSFRichTextString richTextString = new XSSFRichTextString(tempCellData.getStringValue());
+ tempCellData.setStringValue(richTextString.toString());
+ }
+
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java
new file mode 100644
index 0000000..fe5a642
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java
@@ -0,0 +1,57 @@
+package com.alibaba.excel.analysis.v07.handlers;
+
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.xml.sax.Attributes;
+
+import com.alibaba.excel.constant.BuiltinFormats;
+import com.alibaba.excel.constant.ExcelXmlConstants;
+import com.alibaba.excel.context.xlsx.XlsxReadContext;
+import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.metadata.CellData;
+import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder;
+import com.alibaba.excel.util.PositionUtils;
+import com.alibaba.excel.util.StringUtils;
+
+/**
+ * Cell Handler
+ *
+ * @author jipengfei
+ */
+public class CellTagHandler extends AbstractXlsxTagHandler {
+
+ private static final int DEFAULT_FORMAT_INDEX = 0;
+
+ @Override
+ public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) {
+ XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder();
+ xlsxReadSheetHolder.setColumnIndex(PositionUtils.getCol(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R),
+ xlsxReadSheetHolder.getColumnIndex()));
+
+ // t="s" ,it's means String
+ // t="str" ,it's means String,but does not need to be read in the 'sharedStrings.xml'
+ // t="inlineStr" ,it's means String
+ // t="b" ,it's means Boolean
+ // t="e" ,it's means Error
+ // t="n" ,it's means Number
+ // t is null ,it's means Empty or Number
+ CellDataTypeEnum type = CellDataTypeEnum.buildFromCellType(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_T));
+ xlsxReadSheetHolder.setTempCellData(new CellData(type));
+ xlsxReadSheetHolder.setTempData(new StringBuilder());
+
+ // Put in data transformation information
+ String dateFormatIndex = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_S);
+ Integer dateFormatIndexInteger;
+ if (StringUtils.isEmpty(dateFormatIndex)) {
+ dateFormatIndexInteger = DEFAULT_FORMAT_INDEX;
+ } else {
+ dateFormatIndexInteger = Integer.parseInt(dateFormatIndex);
+ }
+ XSSFCellStyle xssfCellStyle =
+ xlsxReadContext.xlsxReadWorkbookHolder().getStylesTable().getStyleAt(dateFormatIndexInteger);
+ int dataFormat = xssfCellStyle.getDataFormat();
+ xlsxReadSheetHolder.getTempCellData().setDataFormat(dataFormat);
+ xlsxReadSheetHolder.getTempCellData().setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat,
+ xssfCellStyle.getDataFormatString(), xlsxReadSheetHolder.getGlobalConfiguration().getLocale()));
+ }
+
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellValueTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellValueTagHandler.java
new file mode 100644
index 0000000..09c9264
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellValueTagHandler.java
@@ -0,0 +1,34 @@
+package com.alibaba.excel.analysis.v07.handlers;
+
+import com.alibaba.excel.context.xlsx.XlsxReadContext;
+import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.metadata.CellData;
+
+/**
+ * Cell Value Handler
+ *
+ * @author jipengfei
+ */
+public class CellValueTagHandler extends AbstractCellValueTagHandler {
+
+ @Override
+ protected void setStringValue(XlsxReadContext xlsxReadContext) {
+ // Have to go "sharedStrings.xml" and get it
+ CellData tempCellData = xlsxReadContext.xlsxReadSheetHolder().getTempCellData();
+ switch (tempCellData.getType()) {
+ case STRING:
+ String stringValue = xlsxReadContext.readWorkbookHolder().getReadCache()
+ .get(Integer.valueOf(tempCellData.getStringValue()));
+ if (stringValue != null && xlsxReadContext.currentReadHolder().globalConfiguration().getAutoTrim()) {
+ stringValue = stringValue.trim();
+ }
+ tempCellData.setStringValue(stringValue);
+ break;
+ case DIRECT_STRING:
+ tempCellData.setType(CellDataTypeEnum.STRING);
+ break;
+ default:
+ }
+ }
+
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java
deleted file mode 100644
index b94483f..0000000
--- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.alibaba.excel.analysis.v07.handlers;
-
-import static com.alibaba.excel.constant.ExcelXmlConstants.DIMENSION;
-import static com.alibaba.excel.constant.ExcelXmlConstants.DIMENSION_REF;
-
-import org.xml.sax.Attributes;
-
-import com.alibaba.excel.analysis.v07.XlsxCellHandler;
-import com.alibaba.excel.context.AnalysisContext;
-
-/**
- * Cell Handler
- *
- * @author jipengfei
- */
-public class CountRowCellHandler implements XlsxCellHandler {
-
- private final AnalysisContext analysisContext;
-
- public CountRowCellHandler(AnalysisContext analysisContext) {
- this.analysisContext = analysisContext;
- }
-
- @Override
- public boolean support(String name) {
- return DIMENSION.equals(name);
- }
-
- @Override
- public void startHandle(String name, Attributes attributes) {
- String d = attributes.getValue(DIMENSION_REF);
- String totalStr = d.substring(d.indexOf(":") + 1, d.length());
- String c = totalStr.toUpperCase().replaceAll("[A-Z]", "");
- analysisContext.readSheetHolder().setApproximateTotalRowNumber(Integer.parseInt(c));
- }
-
- @Override
- public void endHandle(String name) {
-
- }
-
-}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountTagHandler.java
new file mode 100644
index 0000000..823bafb
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountTagHandler.java
@@ -0,0 +1,23 @@
+package com.alibaba.excel.analysis.v07.handlers;
+
+import org.xml.sax.Attributes;
+
+import com.alibaba.excel.constant.ExcelXmlConstants;
+import com.alibaba.excel.context.xlsx.XlsxReadContext;
+
+/**
+ * Cell Handler
+ *
+ * @author jipengfei
+ */
+public class CountTagHandler extends AbstractXlsxTagHandler {
+
+ @Override
+ public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) {
+ String d = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_REF);
+ String totalStr = d.substring(d.indexOf(":") + 1, d.length());
+ String c = totalStr.toUpperCase().replaceAll("[A-Z]", "");
+ xlsxReadContext.readSheetHolder().setApproximateTotalRowNumber(Integer.parseInt(c));
+ }
+
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java
deleted file mode 100644
index e53c3cc..0000000
--- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java
+++ /dev/null
@@ -1,186 +0,0 @@
-package com.alibaba.excel.analysis.v07.handlers;
-
-import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_DATA_FORMAT_TAG;
-import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_FORMULA_TAG;
-import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_INLINE_STRING_VALUE_TAG;
-import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_TAG;
-import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_VALUE_TAG;
-import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_VALUE_TYPE_TAG;
-
-import java.math.BigDecimal;
-import java.util.Deque;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.Map;
-
-import org.apache.poi.ss.usermodel.BuiltinFormats;
-import org.apache.poi.xssf.model.StylesTable;
-import org.apache.poi.xssf.usermodel.XSSFCellStyle;
-import org.apache.poi.xssf.usermodel.XSSFRichTextString;
-import org.xml.sax.Attributes;
-
-import com.alibaba.excel.analysis.v07.XlsxCellHandler;
-import com.alibaba.excel.analysis.v07.XlsxRowResultHolder;
-import com.alibaba.excel.constant.ExcelXmlConstants;
-import com.alibaba.excel.context.AnalysisContext;
-import com.alibaba.excel.enums.CellDataTypeEnum;
-import com.alibaba.excel.metadata.CellData;
-import com.alibaba.excel.util.BooleanUtils;
-import com.alibaba.excel.util.PositionUtils;
-
-/**
- * Cell Handler
- *
- * @author jipengfei
- */
-public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder {
- private final AnalysisContext analysisContext;
- private Deque currentTagDeque = new LinkedList();
- private int curCol = -1;
- private Map curRowContent = new LinkedHashMap();
- private CellData currentCellData;
- private StringBuilder dataStringBuilder;
- private StringBuilder formulaStringBuilder;
-
- /**
- * Current style information
- */
- private StylesTable stylesTable;
-
- public DefaultCellHandler(AnalysisContext analysisContext, StylesTable stylesTable) {
- this.analysisContext = analysisContext;
- this.stylesTable = stylesTable;
- }
-
- @Override
- public void clearResult() {
- curRowContent = new LinkedHashMap();
- curCol=-1;
- }
-
- @Override
- public boolean support(String name) {
- return CELL_VALUE_TAG.equals(name) || CELL_FORMULA_TAG.equals(name) || CELL_INLINE_STRING_VALUE_TAG.equals(name)
- || CELL_TAG.equals(name);
- }
-
- @Override
- public void startHandle(String name, Attributes attributes) {
- currentTagDeque.push(name);
- // start a cell
- if (CELL_TAG.equals(name)) {
- curCol = PositionUtils.getCol(attributes.getValue(ExcelXmlConstants.POSITION),curCol);
-
-
- // t="s" ,it's means String
- // t="str" ,it's means String,but does not need to be read in the 'sharedStrings.xml'
- // t="inlineStr" ,it's means String
- // t="b" ,it's means Boolean
- // t="e" ,it's means Error
- // t="n" ,it's means Number
- // t is null ,it's means Empty or Number
- CellDataTypeEnum type = CellDataTypeEnum.buildFromCellType(attributes.getValue(CELL_VALUE_TYPE_TAG));
- currentCellData = new CellData(type);
- dataStringBuilder = new StringBuilder();
-
- // Put in data transformation information
- String dateFormatIndex = attributes.getValue(CELL_DATA_FORMAT_TAG);
- if (dateFormatIndex != null) {
- int dateFormatIndexInteger = Integer.parseInt(dateFormatIndex);
- XSSFCellStyle xssfCellStyle = stylesTable.getStyleAt(dateFormatIndexInteger);
- int dataFormat = xssfCellStyle.getDataFormat();
- String dataFormatString = xssfCellStyle.getDataFormatString();
- currentCellData.setDataFormat(dataFormat);
- if (dataFormatString == null) {
- currentCellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat));
- } else {
- currentCellData.setDataFormatString(dataFormatString);
- }
- }
- }
- // cell is formula
- if (CELL_FORMULA_TAG.equals(name)) {
- currentCellData.setFormula(Boolean.TRUE);
- formulaStringBuilder = new StringBuilder();
- }
- }
-
- @Override
- public void endHandle(String name) {
- currentTagDeque.pop();
- // cell is formula
- if (CELL_FORMULA_TAG.equals(name)) {
- currentCellData.setFormulaValue(formulaStringBuilder.toString());
- return;
- }
- if (CELL_VALUE_TAG.equals(name) || CELL_INLINE_STRING_VALUE_TAG.equals(name)) {
- CellDataTypeEnum oldType = currentCellData.getType();
- switch (oldType) {
- case DIRECT_STRING:
- case STRING:
- case ERROR:
- currentCellData.setStringValue(dataStringBuilder.toString());
- break;
- case BOOLEAN:
- currentCellData.setBooleanValue(BooleanUtils.valueOf(dataStringBuilder.toString()));
- break;
- case NUMBER:
- case EMPTY:
- currentCellData.setType(CellDataTypeEnum.NUMBER);
- currentCellData.setNumberValue(new BigDecimal(dataStringBuilder.toString()));
- break;
- default:
- throw new IllegalStateException("Cannot set values now");
- }
-
- if (CELL_VALUE_TAG.equals(name)) {
- // Have to go "sharedStrings.xml" and get it
- if (currentCellData.getType() == CellDataTypeEnum.STRING) {
- String stringValue = analysisContext.readWorkbookHolder().getReadCache()
- .get(Integer.valueOf(currentCellData.getStringValue()));
- if (stringValue != null
- && analysisContext.currentReadHolder().globalConfiguration().getAutoTrim()) {
- stringValue = stringValue.trim();
- }
- currentCellData.setStringValue(stringValue);
- } else if (currentCellData.getType() == CellDataTypeEnum.DIRECT_STRING) {
- currentCellData.setType(CellDataTypeEnum.STRING);
- }
- }
- // This is a special form of string
- if (CELL_INLINE_STRING_VALUE_TAG.equals(name)) {
- XSSFRichTextString richTextString = new XSSFRichTextString(currentCellData.getStringValue());
- String stringValue = richTextString.toString();
- if (stringValue != null && analysisContext.currentReadHolder().globalConfiguration().getAutoTrim()) {
- stringValue = stringValue.trim();
- }
- currentCellData.setStringValue(stringValue);
- }
-
- currentCellData.checkEmpty();
- curRowContent.put(curCol, currentCellData);
- }
- }
-
- @Override
- public void appendCurrentCellValue(char[] ch, int start, int length) {
- String currentTag = currentTagDeque.peek();
- if (currentTag == null) {
- return;
- }
- if (CELL_FORMULA_TAG.equals(currentTag)) {
- formulaStringBuilder.append(ch, start, length);
- return;
- }
- if (!CELL_VALUE_TAG.equals(currentTag) && !CELL_INLINE_STRING_VALUE_TAG.equals(currentTag)) {
- return;
- }
- dataStringBuilder.append(ch, start, length);
- }
-
- @Override
- public Map getCurRowContent() {
- return curRowContent;
- }
-
-}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/HyperlinkTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/HyperlinkTagHandler.java
new file mode 100644
index 0000000..ee0154e
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/HyperlinkTagHandler.java
@@ -0,0 +1,35 @@
+package com.alibaba.excel.analysis.v07.handlers;
+
+import org.xml.sax.Attributes;
+
+import com.alibaba.excel.constant.ExcelXmlConstants;
+import com.alibaba.excel.context.xlsx.XlsxReadContext;
+import com.alibaba.excel.enums.CellExtraTypeEnum;
+import com.alibaba.excel.metadata.CellExtra;
+import com.alibaba.excel.util.StringUtils;
+
+/**
+ * Cell Handler
+ *
+ * @author Jiaju Zhuang
+ */
+public class HyperlinkTagHandler extends AbstractXlsxTagHandler {
+
+ @Override
+ public boolean support(XlsxReadContext xlsxReadContext) {
+ return xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.HYPERLINK);
+ }
+
+ @Override
+ public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) {
+ String ref = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_REF);
+ String location = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_LOCATION);
+ if (StringUtils.isEmpty(ref)) {
+ return;
+ }
+ CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.HYPERLINK, location, ref);
+ xlsxReadContext.readSheetHolder().setCellExtra(cellExtra);
+ xlsxReadContext.analysisEventProcessor().extra(xlsxReadContext);
+ }
+
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/MergeCellTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/MergeCellTagHandler.java
new file mode 100644
index 0000000..8b0fa04
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/MergeCellTagHandler.java
@@ -0,0 +1,34 @@
+package com.alibaba.excel.analysis.v07.handlers;
+
+import org.xml.sax.Attributes;
+
+import com.alibaba.excel.constant.ExcelXmlConstants;
+import com.alibaba.excel.context.xlsx.XlsxReadContext;
+import com.alibaba.excel.enums.CellExtraTypeEnum;
+import com.alibaba.excel.metadata.CellExtra;
+import com.alibaba.excel.util.StringUtils;
+
+/**
+ * Cell Handler
+ *
+ * @author Jiaju Zhuang
+ */
+public class MergeCellTagHandler extends AbstractXlsxTagHandler {
+
+ @Override
+ public boolean support(XlsxReadContext xlsxReadContext) {
+ return xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.MERGE);
+ }
+
+ @Override
+ public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) {
+ String ref = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_REF);
+ if (StringUtils.isEmpty(ref)) {
+ return;
+ }
+ CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.MERGE, null, ref);
+ xlsxReadContext.readSheetHolder().setCellExtra(cellExtra);
+ xlsxReadContext.analysisEventProcessor().extra(xlsxReadContext);
+ }
+
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java
deleted file mode 100644
index c854242..0000000
--- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.alibaba.excel.analysis.v07.handlers;
-
-import static com.alibaba.excel.constant.ExcelXmlConstants.ROW_TAG;
-
-import org.xml.sax.Attributes;
-
-import com.alibaba.excel.analysis.v07.XlsxCellHandler;
-import com.alibaba.excel.analysis.v07.XlsxRowResultHolder;
-import com.alibaba.excel.constant.ExcelXmlConstants;
-import com.alibaba.excel.context.AnalysisContext;
-import com.alibaba.excel.read.listener.event.EachRowAnalysisFinishEvent;
-import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
-import com.alibaba.excel.util.PositionUtils;
-
-/**
- * Cell Handler
- *
- * @author jipengfei
- */
-public class ProcessResultCellHandler implements XlsxCellHandler {
- private AnalysisContext analysisContext;
- private XlsxRowResultHolder rowResultHandler;
- private int currentRow = -1;
-
- public ProcessResultCellHandler(AnalysisContext analysisContext, XlsxRowResultHolder rowResultHandler) {
- this.analysisContext = analysisContext;
- this.rowResultHandler = rowResultHandler;
- }
-
- @Override
- public boolean support(String name) {
- return ROW_TAG.equals(name);
- }
-
- @Override
- public void startHandle(String name, Attributes attributes) {
- currentRow = PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.POSITION),currentRow);
- analysisContext.readRowHolder(
- new ReadRowHolder(currentRow, analysisContext.readSheetHolder().getGlobalConfiguration()));
- }
-
- @Override
- public void endHandle(String name) {
- analysisContext.readSheetHolder()
- .notifyEndOneRow(new EachRowAnalysisFinishEvent(rowResultHandler.getCurRowContent()), analysisContext);
- rowResultHandler.clearResult();
- }
-
-}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java
new file mode 100644
index 0000000..61f3873
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java
@@ -0,0 +1,51 @@
+package com.alibaba.excel.analysis.v07.handlers;
+
+import java.util.LinkedHashMap;
+
+import org.xml.sax.Attributes;
+
+import com.alibaba.excel.constant.ExcelXmlConstants;
+import com.alibaba.excel.context.xlsx.XlsxReadContext;
+import com.alibaba.excel.enums.RowTypeEnum;
+import com.alibaba.excel.metadata.Cell;
+import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
+import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder;
+import com.alibaba.excel.util.PositionUtils;
+
+/**
+ * Cell Handler
+ *
+ * @author jipengfei
+ */
+public class RowTagHandler extends AbstractXlsxTagHandler {
+
+ @Override
+ public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) {
+ XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder();
+ int rowIndex = PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R),
+ xlsxReadSheetHolder.getRowIndex());
+ Integer lastRowIndex = xlsxReadContext.readSheetHolder().getRowIndex();
+ if (lastRowIndex != null) {
+ while (lastRowIndex + 1 < rowIndex) {
+ xlsxReadContext.readRowHolder(new ReadRowHolder(lastRowIndex + 1, RowTypeEnum.EMPTY,
+ xlsxReadSheetHolder.getGlobalConfiguration(), new LinkedHashMap()));
+ xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext);
+ xlsxReadSheetHolder.setColumnIndex(null);
+ xlsxReadSheetHolder.setCellMap(new LinkedHashMap());
+ lastRowIndex++;
+ }
+ }
+ xlsxReadSheetHolder.setRowIndex(rowIndex);
+ }
+
+ @Override
+ public void endElement(XlsxReadContext xlsxReadContext, String name) {
+ XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder();
+ xlsxReadContext.readRowHolder(new ReadRowHolder(xlsxReadSheetHolder.getRowIndex(), RowTypeEnum.DATA,
+ xlsxReadSheetHolder.getGlobalConfiguration(), xlsxReadSheetHolder.getCellMap()));
+ xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext);
+ xlsxReadSheetHolder.setColumnIndex(null);
+ xlsxReadSheetHolder.setCellMap(new LinkedHashMap());
+ }
+
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxTagHandler.java
new file mode 100644
index 0000000..fe392f9
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxTagHandler.java
@@ -0,0 +1,54 @@
+package com.alibaba.excel.analysis.v07.handlers;
+
+import org.xml.sax.Attributes;
+
+import com.alibaba.excel.context.xlsx.XlsxReadContext;
+
+/**
+ * Tag handler
+ *
+ * @author Dan Zheng
+ */
+public interface XlsxTagHandler {
+
+ /**
+ * Whether to support
+ *
+ * @param xlsxReadContext
+ * @return
+ */
+ boolean support(XlsxReadContext xlsxReadContext);
+
+ /**
+ * Start handle
+ *
+ * @param xlsxReadContext
+ * xlsxReadContext
+ * @param name
+ * Tag name
+ * @param attributes
+ * Tag attributes
+ */
+ void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes);
+
+ /**
+ * End handle
+ *
+ * @param xlsxReadContext
+ * xlsxReadContext
+ * @param name
+ * Tag name
+ */
+ void endElement(XlsxReadContext xlsxReadContext, String name);
+
+ /**
+ * Read data
+ *
+ * @param xlsxReadContext
+ * @param ch
+ * @param start
+ * @param length
+ */
+ void characters(XlsxReadContext xlsxReadContext, char[] ch, int start, int length);
+
+}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/SharedStringsTableHandler.java
similarity index 97%
rename from src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java
rename to src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/SharedStringsTableHandler.java
index 5e001ed..ea6ffc5 100644
--- a/src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java
+++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/SharedStringsTableHandler.java
@@ -1,4 +1,4 @@
-package com.alibaba.excel.analysis.v07;
+package com.alibaba.excel.analysis.v07.handlers.sax;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/XlsxRowHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/XlsxRowHandler.java
new file mode 100644
index 0000000..65eaa6a
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/XlsxRowHandler.java
@@ -0,0 +1,93 @@
+package com.alibaba.excel.analysis.v07.handlers.sax;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import com.alibaba.excel.analysis.v07.handlers.CellFormulaTagHandler;
+import com.alibaba.excel.analysis.v07.handlers.CellInlineStringValueTagHandler;
+import com.alibaba.excel.analysis.v07.handlers.CellTagHandler;
+import com.alibaba.excel.analysis.v07.handlers.CellValueTagHandler;
+import com.alibaba.excel.analysis.v07.handlers.CountTagHandler;
+import com.alibaba.excel.analysis.v07.handlers.HyperlinkTagHandler;
+import com.alibaba.excel.analysis.v07.handlers.MergeCellTagHandler;
+import com.alibaba.excel.analysis.v07.handlers.RowTagHandler;
+import com.alibaba.excel.analysis.v07.handlers.XlsxTagHandler;
+import com.alibaba.excel.constant.ExcelXmlConstants;
+import com.alibaba.excel.context.xlsx.XlsxReadContext;
+
+/**
+ * @author jipengfei
+ */
+public class XlsxRowHandler extends DefaultHandler {
+ private XlsxReadContext xlsxReadContext;
+ private static final Map XLSX_CELL_HANDLER_MAP = new HashMap(32);
+
+ static {
+ CellFormulaTagHandler cellFormulaTagHandler = new CellFormulaTagHandler();
+ XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_FORMULA_TAG, cellFormulaTagHandler);
+ XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_CELL_FORMULA_TAG, cellFormulaTagHandler);
+ CellInlineStringValueTagHandler cellInlineStringValueTagHandler = new CellInlineStringValueTagHandler();
+ XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_INLINE_STRING_VALUE_TAG, cellInlineStringValueTagHandler);
+ XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_CELL_INLINE_STRING_VALUE_TAG, cellInlineStringValueTagHandler);
+ CellTagHandler cellTagHandler = new CellTagHandler();
+ XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_TAG, cellTagHandler);
+ XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_CELL_TAG, cellTagHandler);
+ CellValueTagHandler cellValueTagHandler = new CellValueTagHandler();
+ XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_VALUE_TAG, cellValueTagHandler);
+ XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_CELL_VALUE_TAG, cellValueTagHandler);
+ CountTagHandler countTagHandler = new CountTagHandler();
+ XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.DIMENSION_TAG, countTagHandler);
+ XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_DIMENSION_TAG, countTagHandler);
+ HyperlinkTagHandler hyperlinkTagHandler = new HyperlinkTagHandler();
+ XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.HYPERLINK_TAG, hyperlinkTagHandler);
+ XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_HYPERLINK_TAG, hyperlinkTagHandler);
+ MergeCellTagHandler mergeCellTagHandler = new MergeCellTagHandler();
+ XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.MERGE_CELL_TAG, mergeCellTagHandler);
+ XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_MERGE_CELL_TAG, mergeCellTagHandler);
+ RowTagHandler rowTagHandler = new RowTagHandler();
+ XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.ROW_TAG, rowTagHandler);
+ XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_ROW_TAG, rowTagHandler);
+ }
+
+ public XlsxRowHandler(XlsxReadContext xlsxReadContext) {
+ this.xlsxReadContext = xlsxReadContext;
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
+ XlsxTagHandler handler = XLSX_CELL_HANDLER_MAP.get(name);
+ if (handler == null || !handler.support(xlsxReadContext)) {
+ return;
+ }
+ xlsxReadContext.xlsxReadSheetHolder().getTagDeque().push(name);
+ handler.startElement(xlsxReadContext, name, attributes);
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ String currentTag = xlsxReadContext.xlsxReadSheetHolder().getTagDeque().peek();
+ if (currentTag == null) {
+ return;
+ }
+ XlsxTagHandler handler = XLSX_CELL_HANDLER_MAP.get(currentTag);
+ if (handler == null || !handler.support(xlsxReadContext)) {
+ return;
+ }
+ handler.characters(xlsxReadContext, ch, start, length);
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String name) throws SAXException {
+ XlsxTagHandler handler = XLSX_CELL_HANDLER_MAP.get(name);
+ if (handler == null || !handler.support(xlsxReadContext)) {
+ return;
+ }
+ handler.endElement(xlsxReadContext, name);
+ xlsxReadContext.xlsxReadSheetHolder().getTagDeque().pop();
+ }
+
+}
diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java b/src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java
new file mode 100644
index 0000000..d593aef
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java
@@ -0,0 +1,89 @@
+package com.alibaba.excel.annotation.write.style;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.poi.common.usermodel.fonts.FontCharset;
+import org.apache.poi.hssf.usermodel.HSSFPalette;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+/**
+ * Custom content styles.
+ *
+ * @author Jiaju Zhuang
+ */
+@Target({ElementType.FIELD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface ContentFontStyle {
+
+ /**
+ * The name for the font (i.e. Arial)
+ */
+ String fontName() default "";
+
+ /**
+ * Height in the familiar unit of measure - points
+ */
+ short fontHeightInPoints() default -1;
+
+ /**
+ * Whether to use italics or not
+ */
+ boolean italic() default false;
+
+ /**
+ * Whether to use a strikeout horizontal line through the text or not
+ */
+ boolean strikeout() default false;
+
+ /**
+ * The color for the font
+ *
+ * @see Font#COLOR_NORMAL
+ * @see Font#COLOR_RED
+ * @see HSSFPalette#getColor(short)
+ * @see IndexedColors
+ */
+ short color() default -1;
+
+ /**
+ * Set normal,super or subscript.
+ *
+ * @see Font#SS_NONE
+ * @see Font#SS_SUPER
+ * @see Font#SS_SUB
+ */
+ short typeOffset() default -1;
+
+ /**
+ * set type of text underlining to use
+ *
+ * @see Font#U_NONE
+ * @see Font#U_SINGLE
+ * @see Font#U_DOUBLE
+ * @see Font#U_SINGLE_ACCOUNTING
+ * @see Font#U_DOUBLE_ACCOUNTING
+ */
+
+ byte underline() default -1;
+
+ /**
+ * Set character-set to use.
+ *
+ * @see FontCharset
+ * @see Font#ANSI_CHARSET
+ * @see Font#DEFAULT_CHARSET
+ * @see Font#SYMBOL_CHARSET
+ */
+ int charset() default -1;
+
+ /**
+ * Bold
+ */
+ boolean bold() default false;
+}
diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/ContentLoopMerge.java b/src/main/java/com/alibaba/excel/annotation/write/style/ContentLoopMerge.java
new file mode 100644
index 0000000..af7bcec
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/annotation/write/style/ContentLoopMerge.java
@@ -0,0 +1,31 @@
+package com.alibaba.excel.annotation.write.style;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The regions of the loop merge
+ *
+ * @author Jiaju Zhuang
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface ContentLoopMerge {
+ /**
+ * Each row
+ *
+ * @return
+ */
+ int eachRow() default -1;
+
+ /**
+ * Extend column
+ *
+ * @return
+ */
+ int columnExtend() default 1;
+}
diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java b/src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java
new file mode 100644
index 0000000..9ef3f47
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java
@@ -0,0 +1,159 @@
+package com.alibaba.excel.annotation.write.style;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.BuiltinFormats;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IgnoredErrorType;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+
+/**
+ * Custom content styles
+ *
+ * @author Jiaju Zhuang
+ */
+@Target({ElementType.FIELD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface ContentStyle {
+ /**
+ * Set the data format (must be a valid format). Built in formats are defined at {@link BuiltinFormats}.
+ */
+ short dataFormat() default -1;
+
+ /**
+ * Set the cell's using this style to be hidden
+ */
+ boolean hidden() default false;
+
+ /**
+ * Set the cell's using this style to be locked
+ */
+ boolean locked() default false;
+
+ /**
+ * Turn on or off "Quote Prefix" or "123 Prefix" for the style, which is used to tell Excel that the thing which
+ * looks like a number or a formula shouldn't be treated as on. Turning this on is somewhat (but not completely, see
+ * {@link IgnoredErrorType}) like prefixing the cell value with a ' in Excel
+ */
+ boolean quotePrefix() default false;
+
+ /**
+ * Set the type of horizontal alignment for the cell
+ */
+ HorizontalAlignment horizontalAlignment() default HorizontalAlignment.GENERAL;
+
+ /**
+ * Set whether the text should be wrapped. Setting this flag to true
make all content visible within a
+ * cell by displaying it on multiple lines
+ *
+ */
+ boolean wrapped() default false;
+
+ /**
+ * Set the type of vertical alignment for the cell
+ */
+ VerticalAlignment verticalAlignment() default VerticalAlignment.CENTER;
+
+ /**
+ * Set the degree of rotation for the text in the cell.
+ *
+ * Note: HSSF uses values from -90 to 90 degrees, whereas XSSF uses values from 0 to 180 degrees. The
+ * implementations of this method will map between these two value-ranges accordingly, however the corresponding
+ * getter is returning values in the range mandated by the current type of Excel file-format that this CellStyle is
+ * applied to.
+ */
+ short rotation() default -1;
+
+ /**
+ * Set the number of spaces to indent the text in the cell
+ */
+ short indent() default -1;
+
+ /**
+ * Set the type of border to use for the left border of the cell
+ */
+ BorderStyle borderLeft() default BorderStyle.NONE;
+
+ /**
+ * Set the type of border to use for the right border of the cell
+ */
+ BorderStyle borderRight() default BorderStyle.NONE;
+
+ /**
+ * Set the type of border to use for the top border of the cell
+ */
+ BorderStyle borderTop() default BorderStyle.NONE;
+
+ /**
+ * Set the type of border to use for the bottom border of the cell
+ */
+ BorderStyle borderBottom() default BorderStyle.NONE;
+
+ /**
+ * Set the color to use for the left border
+ *
+ * @see IndexedColors
+ */
+ short leftBorderColor() default -1;
+
+ /**
+ * Set the color to use for the right border
+ *
+ * @see IndexedColors
+ *
+ */
+ short rightBorderColor() default -1;
+
+ /**
+ * Set the color to use for the top border
+ *
+ * @see IndexedColors
+ *
+ */
+ short topBorderColor() default -1;
+
+ /**
+ * Set the color to use for the bottom border
+ *
+ * @see IndexedColors
+ *
+ */
+ short bottomBorderColor() default -1;
+
+ /**
+ * Setting to one fills the cell with the foreground color... No idea about other values
+ *
+ * @see FillPatternType#SOLID_FOREGROUND
+ */
+ FillPatternType fillPatternType() default FillPatternType.NO_FILL;
+
+ /**
+ * Set the background fill color.
+ *
+ * @see IndexedColors
+ *
+ */
+ short fillBackgroundColor() default -1;
+
+ /**
+ * Set the foreground fill color Note: Ensure Foreground color is set prior to background color.
+ *
+ * @see IndexedColors
+ *
+ */
+ short fillForegroundColor() default -1;
+
+ /**
+ * Controls if the Cell should be auto-sized to shrink to fit if the text is too long
+ */
+ boolean shrinkToFit() default false;
+
+}
diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java b/src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java
new file mode 100644
index 0000000..957e50f
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java
@@ -0,0 +1,89 @@
+package com.alibaba.excel.annotation.write.style;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.poi.common.usermodel.fonts.FontCharset;
+import org.apache.poi.hssf.usermodel.HSSFPalette;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+/**
+ * Custom header styles.
+ *
+ * @author Jiaju Zhuang
+ */
+@Target({ElementType.FIELD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface HeadFontStyle {
+
+ /**
+ * The name for the font (i.e. Arial)
+ */
+ String fontName() default "宋体";
+
+ /**
+ * Height in the familiar unit of measure - points
+ */
+ short fontHeightInPoints() default 14;
+
+ /**
+ * Whether to use italics or not
+ */
+ boolean italic() default false;
+
+ /**
+ * Whether to use a strikeout horizontal line through the text or not
+ */
+ boolean strikeout() default false;
+
+ /**
+ * The color for the font
+ *
+ * @see Font#COLOR_NORMAL
+ * @see Font#COLOR_RED
+ * @see HSSFPalette#getColor(short)
+ * @see IndexedColors
+ */
+ short color() default -1;
+
+ /**
+ * Set normal,super or subscript.
+ *
+ * @see Font#SS_NONE
+ * @see Font#SS_SUPER
+ * @see Font#SS_SUB
+ */
+ short typeOffset() default -1;
+
+ /**
+ * set type of text underlining to use
+ *
+ * @see Font#U_NONE
+ * @see Font#U_SINGLE
+ * @see Font#U_DOUBLE
+ * @see Font#U_SINGLE_ACCOUNTING
+ * @see Font#U_DOUBLE_ACCOUNTING
+ */
+
+ byte underline() default -1;
+
+ /**
+ * Set character-set to use.
+ *
+ * @see FontCharset
+ * @see Font#ANSI_CHARSET
+ * @see Font#DEFAULT_CHARSET
+ * @see Font#SYMBOL_CHARSET
+ */
+ int charset() default -1;
+
+ /**
+ * Bold
+ */
+ boolean bold() default true;
+}
diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java b/src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java
new file mode 100644
index 0000000..d882da8
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java
@@ -0,0 +1,159 @@
+package com.alibaba.excel.annotation.write.style;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.BuiltinFormats;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IgnoredErrorType;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+
+/**
+ * Custom header styles
+ *
+ * @author Jiaju Zhuang
+ */
+@Target({ElementType.FIELD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface HeadStyle {
+ /**
+ * Set the data format (must be a valid format). Built in formats are defined at {@link BuiltinFormats}.
+ */
+ short dataFormat() default -1;
+
+ /**
+ * Set the cell's using this style to be hidden
+ */
+ boolean hidden() default false;
+
+ /**
+ * Set the cell's using this style to be locked
+ */
+ boolean locked() default true;
+
+ /**
+ * Turn on or off "Quote Prefix" or "123 Prefix" for the style, which is used to tell Excel that the thing which
+ * looks like a number or a formula shouldn't be treated as on. Turning this on is somewhat (but not completely, see
+ * {@link IgnoredErrorType}) like prefixing the cell value with a ' in Excel
+ */
+ boolean quotePrefix() default false;
+
+ /**
+ * Set the type of horizontal alignment for the cell
+ */
+ HorizontalAlignment horizontalAlignment() default HorizontalAlignment.CENTER;
+
+ /**
+ * Set whether the text should be wrapped. Setting this flag to true
make all content visible within a
+ * cell by displaying it on multiple lines
+ *
+ */
+ boolean wrapped() default true;
+
+ /**
+ * Set the type of vertical alignment for the cell
+ */
+ VerticalAlignment verticalAlignment() default VerticalAlignment.CENTER;
+
+ /**
+ * Set the degree of rotation for the text in the cell.
+ *
+ * Note: HSSF uses values from -90 to 90 degrees, whereas XSSF uses values from 0 to 180 degrees. The
+ * implementations of this method will map between these two value-ranges accordingly, however the corresponding
+ * getter is returning values in the range mandated by the current type of Excel file-format that this CellStyle is
+ * applied to.
+ */
+ short rotation() default -1;
+
+ /**
+ * Set the number of spaces to indent the text in the cell
+ */
+ short indent() default -1;
+
+ /**
+ * Set the type of border to use for the left border of the cell
+ */
+ BorderStyle borderLeft() default BorderStyle.THIN;
+
+ /**
+ * Set the type of border to use for the right border of the cell
+ */
+ BorderStyle borderRight() default BorderStyle.THIN;
+
+ /**
+ * Set the type of border to use for the top border of the cell
+ */
+ BorderStyle borderTop() default BorderStyle.THIN;
+
+ /**
+ * Set the type of border to use for the bottom border of the cell
+ */
+ BorderStyle borderBottom() default BorderStyle.THIN;
+
+ /**
+ * Set the color to use for the left border
+ *
+ * @see IndexedColors
+ */
+ short leftBorderColor() default -1;
+
+ /**
+ * Set the color to use for the right border
+ *
+ * @see IndexedColors
+ *
+ */
+ short rightBorderColor() default -1;
+
+ /**
+ * Set the color to use for the top border
+ *
+ * @see IndexedColors
+ *
+ */
+ short topBorderColor() default -1;
+
+ /**
+ * Set the color to use for the bottom border
+ *
+ * @see IndexedColors
+ *
+ */
+ short bottomBorderColor() default -1;
+
+ /**
+ * Setting to one fills the cell with the foreground color... No idea about other values
+ *
+ * @see FillPatternType#SOLID_FOREGROUND
+ */
+ FillPatternType fillPatternType() default FillPatternType.SOLID_FOREGROUND;
+
+ /**
+ * Set the background fill color.
+ *
+ * @see IndexedColors
+ *
+ */
+ short fillBackgroundColor() default -1;
+
+ /**
+ * Set the foreground fill color Note: Ensure Foreground color is set prior to background color.
+ *
+ * @see IndexedColors
+ *
+ */
+ short fillForegroundColor() default -1;
+
+ /**
+ * Controls if the Cell should be auto-sized to shrink to fit if the text is too long
+ */
+ boolean shrinkToFit() default false;
+
+}
diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/OnceAbsoluteMerge.java b/src/main/java/com/alibaba/excel/annotation/write/style/OnceAbsoluteMerge.java
new file mode 100644
index 0000000..6c3a148
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/annotation/write/style/OnceAbsoluteMerge.java
@@ -0,0 +1,45 @@
+package com.alibaba.excel.annotation.write.style;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Merge the cells once
+ *
+ * @author Jiaju Zhuang
+ */
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface OnceAbsoluteMerge {
+ /**
+ * First row
+ *
+ * @return
+ */
+ int firstRowIndex() default -1;
+
+ /**
+ * Last row
+ *
+ * @return
+ */
+ int lastRowIndex() default -1;
+
+ /**
+ * First column
+ *
+ * @return
+ */
+ int firstColumnIndex() default -1;
+
+ /**
+ * Last row
+ *
+ * @return
+ */
+ int lastColumnIndex() default -1;
+}
diff --git a/src/main/java/com/alibaba/excel/cache/XlsCache.java b/src/main/java/com/alibaba/excel/cache/XlsCache.java
new file mode 100644
index 0000000..9e814e0
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/cache/XlsCache.java
@@ -0,0 +1,37 @@
+package com.alibaba.excel.cache;
+
+import org.apache.poi.hssf.record.SSTRecord;
+
+import com.alibaba.excel.context.AnalysisContext;
+
+/**
+ *
+ * Use SSTRecord.
+ *
+ * @author Jiaju Zhuang
+ */
+public class XlsCache implements ReadCache {
+ private SSTRecord sstRecord;
+
+ public XlsCache(SSTRecord sstRecord) {
+ this.sstRecord = sstRecord;
+ }
+
+ @Override
+ public void init(AnalysisContext analysisContext) {}
+
+ @Override
+ public void put(String value) {}
+
+ @Override
+ public String get(Integer key) {
+ return sstRecord.getString(key).toString();
+ }
+
+ @Override
+ public void putFinished() {}
+
+ @Override
+ public void destroy() {}
+
+}
diff --git a/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java b/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java
new file mode 100644
index 0000000..95eb0b8
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java
@@ -0,0 +1,379 @@
+package com.alibaba.excel.constant;
+
+import java.util.Locale;
+
+/**
+ * Excel's built-in format conversion.Currently only supports Chinese.
+ *
+ *
+ * If it is not Chinese, it is recommended to directly modify the builtinFormats, which will better support
+ * internationalization in the future.
+ *
+ *
+ * Specific correspondence please see:
+ * https://docs.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.numberingformat?view=openxml-2.8.1
+ *
+ * @author Jiaju Zhuang
+ **/
+public class BuiltinFormats {
+
+ private static final String[] BUILTIN_FORMATS_CN = {
+ // 0
+ "General",
+ // 1
+ "0",
+ // 2
+ "0.00",
+ // 3
+ "#,##0",
+ // 4
+ "#,##0.00",
+ // 5
+ "\"¥\"#,##0_);(\"¥\"#,##0)",
+ // 6
+ "\"¥\"#,##0_);[Red](\"¥\"#,##0)",
+ // 7
+ "\"¥\"#,##0.00_);(\"¥\"#,##0.00)",
+ // 8
+ "\"¥\"#,##0.00_);[Red](\"¥\"#,##0.00)",
+ // 9
+ "0%",
+ // 10
+ "0.00%",
+ // 11
+ "0.00E+00",
+ // 12
+ "# ?/?",
+ // 13
+ "# ??/??",
+ // 14
+ // The official documentation shows "m/d/yy", but the actual test is "yyyy/m/d".
+ "yyyy/m/d",
+ // 15
+ "d-mmm-yy",
+ // 16
+ "d-mmm",
+ // 17
+ "mmm-yy",
+ // 18
+ "h:mm AM/PM",
+ // 19
+ "h:mm:ss AM/PM",
+ // 20
+ "h:mm",
+ // 21
+ "h:mm:ss",
+ // 22
+ // The official documentation shows "m/d/yy h:mm", but the actual test is "yyyy-m-d h:mm".
+ "yyyy-m-d h:mm",
+ // 23-26 No specific correspondence found in the official documentation.
+ // 23
+ null,
+ // 24
+ null,
+ // 25
+ null,
+ // 26
+ null,
+ // 27
+ "yyyy\"年\"m\"月\"",
+ // 28
+ "m\"月\"d\"日\"",
+ // 29
+ "m\"月\"d\"日\"",
+ // 30
+ "m-d-yy",
+ // 31
+ "yyyy\"年\"m\"月\"d\"日\"",
+ // 32
+ "h\"时\"mm\"分\"",
+ // 33
+ "h\"时\"mm\"分\"ss\"秒\"",
+ // 34
+ "上午/下午h\"时\"mm\"分\"",
+ // 35
+ "上午/下午h\"时\"mm\"分\"ss\"秒\"",
+ // 36
+ "yyyy\"年\"m\"月\"",
+ // 37
+ "#,##0_);(#,##0)",
+ // 38
+ "#,##0_);[Red](#,##0)",
+ // 39
+ "#,##0.00_);(#,##0.00)",
+ // 40
+ "#,##0.00_);[Red](#,##0.00)",
+ // 41
+ "_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)",
+ // 42
+ "_(\"¥\"* #,##0_);_(\"¥\"* (#,##0);_(\"¥\"* \"-\"_);_(@_)",
+ // 43
+ "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)",
+ // 44
+ "_(\"¥\"* #,##0.00_);_(\"¥\"* (#,##0.00);_(\"¥\"* \"-\"??_);_(@_)",
+ // 45
+ "mm:ss",
+ // 46
+ "[h]:mm:ss",
+ // 47
+ "mm:ss.0",
+ // 48
+ "##0.0E+0",
+ // 49
+ "@",
+ // 50
+ "yyyy\"年\"m\"月\"",
+ // 51
+ "m\"月\"d\"日\"",
+ // 52
+ "yyyy\"年\"m\"月\"",
+ // 53
+ "m\"月\"d\"日\"",
+ // 54
+ "m\"月\"d\"日\"",
+ // 55
+ "上午/下午h\"时\"mm\"分\"",
+ // 56
+ "上午/下午h\"时\"mm\"分\"ss\"秒\"",
+ // 57
+ "yyyy\"年\"m\"月\"",
+ // 58
+ "m\"月\"d\"日\"",
+ // 59
+ "t0",
+ // 60
+ "t0.00",
+ // 61
+ "t#,##0",
+ // 62
+ "t#,##0.00",
+ // 63-66 No specific correspondence found in the official documentation.
+ // 63
+ null,
+ // 64
+ null,
+ // 65
+ null,
+ // 66
+ null,
+ // 67
+ "t0%",
+ // 68
+ "t0.00%",
+ // 69
+ "t# ?/?",
+ // 70
+ "t# ??/??",
+ // 71
+ "ว/ด/ปปปป",
+ // 72
+ "ว-ดดด-ปป",
+ // 73
+ "ว-ดดด",
+ // 74
+ "ดดด-ปป",
+ // 75
+ "ช:นน",
+ // 76
+ "ช:นน:ทท",
+ // 77
+ "ว/ด/ปปปป ช:นน",
+ // 78
+ "นน:ทท",
+ // 79
+ "[ช]:นน:ทท",
+ // 80
+ "นน:ทท.0",
+ // 81
+ "d/m/bb",
+ // end
+ };
+
+ private static final String[] BUILTIN_FORMATS_US = {
+ // 0
+ "General",
+ // 1
+ "0",
+ // 2
+ "0.00",
+ // 3
+ "#,##0",
+ // 4
+ "#,##0.00",
+ // 5
+ "\"$\"#,##0_);(\"$\"#,##0)",
+ // 6
+ "\"$\"#,##0_);[Red](\"$\"#,##0)",
+ // 7
+ "\"$\"#,##0.00_);(\"$\"#,##0.00)",
+ // 8
+ "\"$\"#,##0.00_);[Red](\"$\"#,##0.00)",
+ // 9
+ "0%",
+ // 10
+ "0.00%",
+ // 11
+ "0.00E+00",
+ // 12
+ "# ?/?",
+ // 13
+ "# ??/??",
+ // 14
+ // The official documentation shows "m/d/yy", but the actual test is "yyyy/m/d".
+ "yyyy/m/d",
+ // 15
+ "d-mmm-yy",
+ // 16
+ "d-mmm",
+ // 17
+ "mmm-yy",
+ // 18
+ "h:mm AM/PM",
+ // 19
+ "h:mm:ss AM/PM",
+ // 20
+ "h:mm",
+ // 21
+ "h:mm:ss",
+ // 22
+ // The official documentation shows "m/d/yy h:mm", but the actual test is "yyyy-m-d h:mm".
+ "yyyy-m-d h:mm",
+ // 23-26 No specific correspondence found in the official documentation.
+ // 23
+ null,
+ // 24
+ null,
+ // 25
+ null,
+ // 26
+ null,
+ // 27
+ "yyyy\"年\"m\"月\"",
+ // 28
+ "m\"月\"d\"日\"",
+ // 29
+ "m\"月\"d\"日\"",
+ // 30
+ "m-d-yy",
+ // 31
+ "yyyy\"年\"m\"月\"d\"日\"",
+ // 32
+ "h\"时\"mm\"分\"",
+ // 33
+ "h\"时\"mm\"分\"ss\"秒\"",
+ // 34
+ "上午/下午h\"时\"mm\"分\"",
+ // 35
+ "上午/下午h\"时\"mm\"分\"ss\"秒\"",
+ // 36
+ "yyyy\"年\"m\"月\"",
+ // 37
+ "#,##0_);(#,##0)",
+ // 38
+ "#,##0_);[Red](#,##0)",
+ // 39
+ "#,##0.00_);(#,##0.00)",
+ // 40
+ "#,##0.00_);[Red](#,##0.00)",
+ // 41
+ "_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)",
+ // 42
+ "_(\"$\"* #,##0_);_(\"$\"* (#,##0);_(\"$\"* \"-\"_);_(@_)",
+ // 43
+ "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)",
+ // 44
+ "_(\"$\"* #,##0.00_);_(\"$\"* (#,##0.00);_(\"$\"* \"-\"??_);_(@_)",
+ // 45
+ "mm:ss",
+ // 46
+ "[h]:mm:ss",
+ // 47
+ "mm:ss.0",
+ // 48
+ "##0.0E+0",
+ // 49
+ "@",
+ // 50
+ "yyyy\"年\"m\"月\"",
+ // 51
+ "m\"月\"d\"日\"",
+ // 52
+ "yyyy\"年\"m\"月\"",
+ // 53
+ "m\"月\"d\"日\"",
+ // 54
+ "m\"月\"d\"日\"",
+ // 55
+ "上午/下午h\"时\"mm\"分\"",
+ // 56
+ "上午/下午h\"时\"mm\"分\"ss\"秒\"",
+ // 57
+ "yyyy\"年\"m\"月\"",
+ // 58
+ "m\"月\"d\"日\"",
+ // 59
+ "t0",
+ // 60
+ "t0.00",
+ // 61
+ "t#,##0",
+ // 62
+ "t#,##0.00",
+ // 63-66 No specific correspondence found in the official documentation.
+ // 63
+ null,
+ // 64
+ null,
+ // 65
+ null,
+ // 66
+ null,
+ // 67
+ "t0%",
+ // 68
+ "t0.00%",
+ // 69
+ "t# ?/?",
+ // 70
+ "t# ??/??",
+ // 71
+ "ว/ด/ปปปป",
+ // 72
+ "ว-ดดด-ปป",
+ // 73
+ "ว-ดดด",
+ // 74
+ "ดดด-ปป",
+ // 75
+ "ช:นน",
+ // 76
+ "ช:นน:ทท",
+ // 77
+ "ว/ด/ปปปป ช:นน",
+ // 78
+ "นน:ทท",
+ // 79
+ "[ช]:นน:ทท",
+ // 80
+ "นน:ทท.0",
+ // 81
+ "d/m/bb",
+ // end
+ };
+
+ public static String getBuiltinFormat(Integer index, String defaultFormat, Locale locale) {
+ String[] builtinFormat = switchBuiltinFormats(locale);
+ if (index == null || index < 0 || index >= builtinFormat.length) {
+ return defaultFormat;
+ }
+ return builtinFormat[index];
+ }
+
+ private static String[] switchBuiltinFormats(Locale locale) {
+ if (locale != null && Locale.US.getCountry().equals(locale.getCountry())) {
+ return BUILTIN_FORMATS_US;
+ }
+ return BUILTIN_FORMATS_CN;
+ }
+
+}
diff --git a/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java b/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java
index f01a33b..38c2005 100644
--- a/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java
+++ b/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java
@@ -4,22 +4,54 @@ package com.alibaba.excel.constant;
* @author jipengfei
*/
public class ExcelXmlConstants {
- public static final String DIMENSION = "dimension";
- public static final String DIMENSION_REF = "ref";
- public static final String POSITION = "r";
-
+ public static final String DIMENSION_TAG = "dimension";
public static final String ROW_TAG = "row";
- public static final String CELL_TAG = "c";
- public static final String CELL_VALUE_TYPE_TAG = "t";
- /**
- * Number formatted label
- */
- public static final String CELL_DATA_FORMAT_TAG = "s";
public static final String CELL_FORMULA_TAG = "f";
public static final String CELL_VALUE_TAG = "v";
/**
* When the data is "inlineStr" his tag is "t"
*/
public static final String CELL_INLINE_STRING_VALUE_TAG = "t";
+ public static final String CELL_TAG = "c";
+ public static final String MERGE_CELL_TAG = "mergeCell";
+ public static final String HYPERLINK_TAG = "hyperlink";
+
+ public static final String X_DIMENSION_TAG = "x:dimension";
+ public static final String X_ROW_TAG = "x:row";
+ public static final String X_CELL_FORMULA_TAG = "x:f";
+ public static final String X_CELL_VALUE_TAG = "x:v";
+ /**
+ * When the data is "inlineStr" his tag is "t"
+ */
+ public static final String X_CELL_INLINE_STRING_VALUE_TAG = "x:t";
+ public static final String X_CELL_TAG = "x:c";
+ public static final String X_MERGE_CELL_TAG = "x:mergeCell";
+ public static final String X_HYPERLINK_TAG = "x:hyperlink";
+
+ /**
+ * s attribute
+ */
+ public static final String ATTRIBUTE_S = "s";
+ /**
+ * ref attribute
+ */
+ public static final String ATTRIBUTE_REF = "ref";
+ /**
+ * r attribute
+ */
+ public static final String ATTRIBUTE_R = "r";
+ /**
+ * t attribute
+ */
+ public static final String ATTRIBUTE_T = "t";
+ /**
+ * location attribute
+ */
+ public static final String ATTRIBUTE_LOCATION = "location";
+
+ /**
+ * Cell range split
+ */
+ public static final String CELL_RANGE_SPLIT = ":";
}
diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContext.java b/src/main/java/com/alibaba/excel/context/AnalysisContext.java
index f44c2b3..df17f55 100644
--- a/src/main/java/com/alibaba/excel/context/AnalysisContext.java
+++ b/src/main/java/com/alibaba/excel/context/AnalysisContext.java
@@ -1,8 +1,8 @@
package com.alibaba.excel.context;
import java.io.InputStream;
+import java.util.List;
-import com.alibaba.excel.analysis.ExcelReadExecutor;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.read.metadata.ReadSheet;
@@ -10,6 +10,7 @@ import com.alibaba.excel.read.metadata.holder.ReadHolder;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.excel.read.metadata.holder.ReadSheetHolder;
import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
+import com.alibaba.excel.read.processor.AnalysisEventProcessor;
import com.alibaba.excel.support.ExcelTypeEnum;
/**
@@ -70,6 +71,27 @@ public interface AnalysisContext {
*/
Object getCustom();
+ /**
+ * Event processor
+ *
+ * @return
+ */
+ AnalysisEventProcessor analysisEventProcessor();
+
+ /**
+ * Data that the customer needs to read
+ *
+ * @return
+ */
+ List readSheetList();
+
+ /**
+ * Data that the customer needs to read
+ *
+ * @param readSheetList
+ */
+ void readSheetList(List readSheetList);
+
/**
* get current sheet
*
diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java
index e5ded50..ab27e87 100644
--- a/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java
+++ b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java
@@ -1,6 +1,7 @@
package com.alibaba.excel.context;
import java.io.InputStream;
+import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -13,6 +14,12 @@ import com.alibaba.excel.read.metadata.holder.ReadHolder;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.excel.read.metadata.holder.ReadSheetHolder;
import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
+import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder;
+import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder;
+import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder;
+import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder;
+import com.alibaba.excel.read.processor.AnalysisEventProcessor;
+import com.alibaba.excel.read.processor.DefaultAnalysisEventProcessor;
import com.alibaba.excel.support.ExcelTypeEnum;
/**
@@ -37,13 +44,27 @@ public class AnalysisContextImpl implements AnalysisContext {
* Configuration of currently operated cell
*/
private ReadHolder currentReadHolder;
+ /**
+ * Event processor
+ */
+ private AnalysisEventProcessor analysisEventProcessor;
- public AnalysisContextImpl(ReadWorkbook readWorkbook) {
+ public AnalysisContextImpl(ReadWorkbook readWorkbook, ExcelTypeEnum actualExcelType) {
if (readWorkbook == null) {
throw new IllegalArgumentException("Workbook argument cannot be null");
}
- readWorkbookHolder = new ReadWorkbookHolder(readWorkbook);
+ switch (actualExcelType) {
+ case XLS:
+ readWorkbookHolder = new XlsReadWorkbookHolder(readWorkbook);
+ break;
+ case XLSX:
+ readWorkbookHolder = new XlsxReadWorkbookHolder(readWorkbook);
+ break;
+ default:
+ break;
+ }
currentReadHolder = readWorkbookHolder;
+ analysisEventProcessor = new DefaultAnalysisEventProcessor();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Initialization 'AnalysisContextImpl' complete");
}
@@ -51,7 +72,16 @@ public class AnalysisContextImpl implements AnalysisContext {
@Override
public void currentSheet(ReadSheet readSheet) {
- readSheetHolder = new ReadSheetHolder(readSheet, readWorkbookHolder);
+ switch (readWorkbookHolder.getExcelType()) {
+ case XLS:
+ readSheetHolder = new XlsReadSheetHolder(readSheet, readWorkbookHolder);
+ break;
+ case XLSX:
+ readSheetHolder = new XlsxReadSheetHolder(readSheet, readWorkbookHolder);
+ break;
+ default:
+ break;
+ }
currentReadHolder = readSheetHolder;
if (readWorkbookHolder.getHasReadSheet().contains(readSheetHolder.getSheetNo())) {
throw new ExcelAnalysisException("Cannot read sheet repeatedly.");
@@ -92,6 +122,21 @@ public class AnalysisContextImpl implements AnalysisContext {
return readWorkbookHolder.getCustomObject();
}
+ @Override
+ public AnalysisEventProcessor analysisEventProcessor() {
+ return analysisEventProcessor;
+ }
+
+ @Override
+ public List readSheetList() {
+ return null;
+ }
+
+ @Override
+ public void readSheetList(List readSheetList) {
+
+ }
+
@Override
public Sheet getCurrentSheet() {
Sheet sheet = new Sheet(readSheetHolder.getSheetNo() + 1);
diff --git a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java
index e79453c..8465cbd 100644
--- a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java
+++ b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java
@@ -27,7 +27,9 @@ import com.alibaba.excel.exception.ExcelGenerateException;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.support.ExcelTypeEnum;
+import com.alibaba.excel.util.DateUtils;
import com.alibaba.excel.util.FileUtils;
+import com.alibaba.excel.util.NumberDataFormatterUtils;
import com.alibaba.excel.util.StringUtils;
import com.alibaba.excel.util.WorkBookUtil;
import com.alibaba.excel.util.WriteHandlerUtils;
@@ -307,7 +309,6 @@ public class WriteContextImpl implements WriteContext {
throwable = t;
}
}
-
if (!isOutputStreamEncrypt) {
try {
if (writeExcel) {
@@ -318,7 +319,6 @@ public class WriteContextImpl implements WriteContext {
throwable = t;
}
}
-
try {
Workbook workbook = writeWorkbookHolder.getWorkbook();
if (workbook instanceof SXSSFWorkbook) {
@@ -327,7 +327,6 @@ public class WriteContextImpl implements WriteContext {
} catch (Throwable t) {
throwable = t;
}
-
try {
if (writeWorkbookHolder.getAutoCloseStream() && writeWorkbookHolder.getOutputStream() != null) {
writeWorkbookHolder.getOutputStream().close();
@@ -335,7 +334,6 @@ public class WriteContextImpl implements WriteContext {
} catch (Throwable t) {
throwable = t;
}
-
if (writeExcel && !isOutputStreamEncrypt) {
try {
doFileEncrypt07();
@@ -343,7 +341,6 @@ public class WriteContextImpl implements WriteContext {
throwable = t;
}
}
-
try {
if (writeWorkbookHolder.getTempTemplateInputStream() != null) {
writeWorkbookHolder.getTempTemplateInputStream().close();
@@ -351,18 +348,21 @@ public class WriteContextImpl implements WriteContext {
} catch (Throwable t) {
throwable = t;
}
-
clearEncrypt03();
-
+ removeThreadLocalCache();
if (throwable != null) {
throw new ExcelGenerateException("Can not close IO.", throwable);
}
-
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Finished write.");
}
}
+ private void removeThreadLocalCache() {
+ NumberDataFormatterUtils.removeThreadLocalCache();
+ DateUtils.removeThreadLocalCache();
+ }
+
@Override
public Sheet getCurrentSheet() {
return writeSheetHolder.getSheet();
diff --git a/src/main/java/com/alibaba/excel/context/xls/DefaultXlsReadContext.java b/src/main/java/com/alibaba/excel/context/xls/DefaultXlsReadContext.java
new file mode 100644
index 0000000..698bf6a
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/context/xls/DefaultXlsReadContext.java
@@ -0,0 +1,30 @@
+package com.alibaba.excel.context.xls;
+
+import com.alibaba.excel.context.AnalysisContextImpl;
+import com.alibaba.excel.read.metadata.ReadWorkbook;
+import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder;
+import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder;
+import com.alibaba.excel.support.ExcelTypeEnum;
+
+/**
+ *
+ * A context is the main anchorage point of a ls xls reader.
+ *
+ * @author Jiaju Zhuang
+ */
+public class DefaultXlsReadContext extends AnalysisContextImpl implements XlsReadContext {
+
+ public DefaultXlsReadContext(ReadWorkbook readWorkbook, ExcelTypeEnum actualExcelType) {
+ super(readWorkbook, actualExcelType);
+ }
+
+ @Override
+ public XlsReadWorkbookHolder xlsReadWorkbookHolder() {
+ return (XlsReadWorkbookHolder)readWorkbookHolder();
+ }
+
+ @Override
+ public XlsReadSheetHolder xlsReadSheetHolder() {
+ return (XlsReadSheetHolder)readSheetHolder();
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/context/xls/XlsReadContext.java b/src/main/java/com/alibaba/excel/context/xls/XlsReadContext.java
new file mode 100644
index 0000000..4d1bcdb
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/context/xls/XlsReadContext.java
@@ -0,0 +1,26 @@
+package com.alibaba.excel.context.xls;
+
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder;
+import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder;
+
+/**
+ * A context is the main anchorage point of a ls xls reader.
+ *
+ * @author Jiaju Zhuang
+ **/
+public interface XlsReadContext extends AnalysisContext {
+ /**
+ * All information about the workbook you are currently working on.
+ *
+ * @return Current workbook holder
+ */
+ XlsReadWorkbookHolder xlsReadWorkbookHolder();
+
+ /**
+ * All information about the sheet you are currently working on.
+ *
+ * @return Current sheet holder
+ */
+ XlsReadSheetHolder xlsReadSheetHolder();
+}
diff --git a/src/main/java/com/alibaba/excel/context/xlsx/DefaultXlsxReadContext.java b/src/main/java/com/alibaba/excel/context/xlsx/DefaultXlsxReadContext.java
new file mode 100644
index 0000000..5c9d638
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/context/xlsx/DefaultXlsxReadContext.java
@@ -0,0 +1,30 @@
+package com.alibaba.excel.context.xlsx;
+
+import com.alibaba.excel.context.AnalysisContextImpl;
+import com.alibaba.excel.read.metadata.ReadWorkbook;
+import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder;
+import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder;
+import com.alibaba.excel.support.ExcelTypeEnum;
+
+/**
+ *
+ * A context is the main anchorage point of a ls xls reader.
+ *
+ * @author Jiaju Zhuang
+ */
+public class DefaultXlsxReadContext extends AnalysisContextImpl implements XlsxReadContext {
+
+ public DefaultXlsxReadContext(ReadWorkbook readWorkbook, ExcelTypeEnum actualExcelType) {
+ super(readWorkbook, actualExcelType);
+ }
+
+ @Override
+ public XlsxReadWorkbookHolder xlsxReadWorkbookHolder() {
+ return (XlsxReadWorkbookHolder)readWorkbookHolder();
+ }
+
+ @Override
+ public XlsxReadSheetHolder xlsxReadSheetHolder() {
+ return (XlsxReadSheetHolder)readSheetHolder();
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/context/xlsx/XlsxReadContext.java b/src/main/java/com/alibaba/excel/context/xlsx/XlsxReadContext.java
new file mode 100644
index 0000000..58d8123
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/context/xlsx/XlsxReadContext.java
@@ -0,0 +1,26 @@
+package com.alibaba.excel.context.xlsx;
+
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder;
+import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder;
+
+/**
+ * A context is the main anchorage point of a ls xlsx reader.
+ *
+ * @author Jiaju Zhuang
+ **/
+public interface XlsxReadContext extends AnalysisContext {
+ /**
+ * All information about the workbook you are currently working on.
+ *
+ * @return Current workbook holder
+ */
+ XlsxReadWorkbookHolder xlsxReadWorkbookHolder();
+
+ /**
+ * All information about the sheet you are currently working on.
+ *
+ * @return Current sheet holder
+ */
+ XlsxReadSheetHolder xlsxReadSheetHolder();
+}
diff --git a/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java b/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java
index 77e8b59..0182255 100644
--- a/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java
+++ b/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java
@@ -48,56 +48,12 @@ public class DefaultConverterLoader {
private static Map defaultWriteConverter;
private static Map allConverter;
- /**
- * Load default write converter
- *
- * @return
- */
- public static Map loadDefaultWriteConverter() {
- if (defaultWriteConverter != null) {
- return defaultWriteConverter;
- }
- defaultWriteConverter = new HashMap(32);
- putWriteConverter(new BigDecimalNumberConverter());
- putWriteConverter(new BooleanBooleanConverter());
- putWriteConverter(new ByteNumberConverter());
- putWriteConverter(new DateStringConverter());
- putWriteConverter(new DoubleNumberConverter());
- putWriteConverter(new FloatNumberConverter());
- putWriteConverter(new IntegerNumberConverter());
- putWriteConverter(new LongNumberConverter());
- putWriteConverter(new ShortNumberConverter());
- putWriteConverter(new StringStringConverter());
- putWriteConverter(new FileImageConverter());
- putWriteConverter(new InputStreamImageConverter());
- putWriteConverter(new ByteArrayImageConverter());
- putWriteConverter(new BoxingByteArrayImageConverter());
- putWriteConverter(new UrlImageConverter());
- return defaultWriteConverter;
+ static {
+ initDefaultWriteConverter();
+ initAllConverter();
}
- private static void putWriteConverter(Converter converter) {
- defaultWriteConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter);
- }
-
- /**
- * Load default read converter
- *
- * @return
- */
- public static Map loadDefaultReadConverter() {
- return loadAllConverter();
- }
-
- /**
- * Load all converter
- *
- * @return
- */
- public static Map loadAllConverter() {
- if (allConverter != null) {
- return allConverter;
- }
+ private static void initAllConverter() {
allConverter = new HashMap(64);
putAllConverter(new BigDecimalBooleanConverter());
putAllConverter(new BigDecimalNumberConverter());
@@ -138,6 +94,55 @@ public class DefaultConverterLoader {
putAllConverter(new StringNumberConverter());
putAllConverter(new StringStringConverter());
putAllConverter(new StringErrorConverter());
+ }
+
+ private static void initDefaultWriteConverter() {
+ defaultWriteConverter = new HashMap(32);
+ putWriteConverter(new BigDecimalNumberConverter());
+ putWriteConverter(new BooleanBooleanConverter());
+ putWriteConverter(new ByteNumberConverter());
+ putWriteConverter(new DateStringConverter());
+ putWriteConverter(new DoubleNumberConverter());
+ putWriteConverter(new FloatNumberConverter());
+ putWriteConverter(new IntegerNumberConverter());
+ putWriteConverter(new LongNumberConverter());
+ putWriteConverter(new ShortNumberConverter());
+ putWriteConverter(new StringStringConverter());
+ putWriteConverter(new FileImageConverter());
+ putWriteConverter(new InputStreamImageConverter());
+ putWriteConverter(new ByteArrayImageConverter());
+ putWriteConverter(new BoxingByteArrayImageConverter());
+ putWriteConverter(new UrlImageConverter());
+ }
+
+ /**
+ * Load default write converter
+ *
+ * @return
+ */
+ public static Map loadDefaultWriteConverter() {
+ return defaultWriteConverter;
+ }
+
+ private static void putWriteConverter(Converter converter) {
+ defaultWriteConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter);
+ }
+
+ /**
+ * Load default read converter
+ *
+ * @return
+ */
+ public static Map loadDefaultReadConverter() {
+ return loadAllConverter();
+ }
+
+ /**
+ * Load all converter
+ *
+ * @return
+ */
+ public static Map loadAllConverter() {
return allConverter;
}
diff --git a/src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java b/src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java
index 8c16a77..f1facdf 100644
--- a/src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java
+++ b/src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java
@@ -34,7 +34,7 @@ public class ByteNumberConverter implements Converter {
@Override
public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
- return new CellData(BigDecimal.valueOf(value));
+ return new CellData(new BigDecimal(Byte.toString(value)));
}
}
diff --git a/src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java b/src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java
index a1b6471..69cc22e 100644
--- a/src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java
+++ b/src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java
@@ -34,7 +34,7 @@ public class FloatNumberConverter implements Converter {
@Override
public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
- return new CellData(BigDecimal.valueOf(value));
+ return new CellData(new BigDecimal(Float.toString(value)));
}
}
diff --git a/src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java b/src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java
index 3b0deac..117d4c1 100644
--- a/src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java
+++ b/src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java
@@ -34,7 +34,7 @@ public class IntegerNumberConverter implements Converter {
@Override
public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
- return new CellData(BigDecimal.valueOf(value));
+ return new CellData(new BigDecimal(Integer.toString(value)));
}
}
diff --git a/src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java b/src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java
index 7d1d7da..357c6ae 100644
--- a/src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java
+++ b/src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java
@@ -34,7 +34,7 @@ public class ShortNumberConverter implements Converter {
@Override
public CellData convertToExcelData(Short value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
- return new CellData(BigDecimal.valueOf(value));
+ return new CellData(new BigDecimal(Short.toString(value)));
}
}
diff --git a/src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java b/src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java
index f536a08..b31bc70 100644
--- a/src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java
+++ b/src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java
@@ -10,7 +10,9 @@ import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.DateUtils;
+import com.alibaba.excel.util.NumberDataFormatterUtils;
import com.alibaba.excel.util.NumberUtils;
+import com.alibaba.excel.util.StringUtils;
/**
* String and number converter
@@ -44,13 +46,9 @@ public class StringNumberConverter implements Converter {
return NumberUtils.format(cellData.getNumberValue(), contentProperty);
}
// Excel defines formatting
- if (cellData.getDataFormat() != null) {
- if (DateUtil.isADateFormat(cellData.getDataFormat(), cellData.getDataFormatString())) {
- return DateUtils.format(DateUtil.getJavaDate(cellData.getNumberValue().doubleValue(),
- globalConfiguration.getUse1904windowing(), null));
- } else {
- return NumberUtils.format(cellData.getNumberValue(), contentProperty);
- }
+ if (cellData.getDataFormat() != null && !StringUtils.isEmpty(cellData.getDataFormatString())) {
+ return NumberDataFormatterUtils.format(cellData.getNumberValue().doubleValue(), cellData.getDataFormat(),
+ cellData.getDataFormatString(), globalConfiguration);
}
// Default conversion number
return NumberUtils.format(cellData.getNumberValue(), contentProperty);
diff --git a/src/main/java/com/alibaba/excel/enums/CellExtraTypeEnum.java b/src/main/java/com/alibaba/excel/enums/CellExtraTypeEnum.java
new file mode 100644
index 0000000..1c13b7c
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/enums/CellExtraTypeEnum.java
@@ -0,0 +1,21 @@
+package com.alibaba.excel.enums;
+
+/**
+ * Extra data type
+ *
+ * @author Jiaju Zhuang
+ **/
+public enum CellExtraTypeEnum {
+ /**
+ * Comment
+ */
+ COMMENT,
+ /**
+ * Hyperlink
+ */
+ HYPERLINK,
+ /**
+ * Merge
+ */
+ MERGE,;
+}
diff --git a/src/main/java/com/alibaba/excel/enums/RowTypeEnum.java b/src/main/java/com/alibaba/excel/enums/RowTypeEnum.java
new file mode 100644
index 0000000..e371cbd
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/enums/RowTypeEnum.java
@@ -0,0 +1,17 @@
+package com.alibaba.excel.enums;
+
+/**
+ * The types of row
+ *
+ * @author Jiaju Zhuang
+ **/
+public enum RowTypeEnum {
+ /**
+ * data
+ */
+ DATA,
+ /**
+ * empty
+ */
+ EMPTY,;
+}
diff --git a/src/main/java/com/alibaba/excel/event/AbstractIgnoreExceptionReadListener.java b/src/main/java/com/alibaba/excel/event/AbstractIgnoreExceptionReadListener.java
index 22a95f0..1e93397 100644
--- a/src/main/java/com/alibaba/excel/event/AbstractIgnoreExceptionReadListener.java
+++ b/src/main/java/com/alibaba/excel/event/AbstractIgnoreExceptionReadListener.java
@@ -1,6 +1,7 @@
package com.alibaba.excel.event;
import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.listener.ReadListener;
/**
@@ -20,6 +21,17 @@ public abstract class AbstractIgnoreExceptionReadListener implements ReadList
@Override
public void onException(Exception exception, AnalysisContext context) {}
+ /**
+ * The current method is called when extra information is returned
+ *
+ * @param extra
+ * extra information
+ * @param context
+ * analysis context
+ */
+ @Override
+ public void extra(CellExtra extra, AnalysisContext context) {}
+
@Override
public boolean hasNext(AnalysisContext context) {
return true;
diff --git a/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java b/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java
index 176bd79..4b1b802 100644
--- a/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java
+++ b/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java
@@ -4,6 +4,7 @@ import java.util.Map;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.CellData;
+import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ConverterUtils;
@@ -27,6 +28,17 @@ public abstract class AnalysisEventListener implements ReadListener {
*/
public void invokeHeadMap(Map headMap, AnalysisContext context) {}
+ /**
+ * The current method is called when extra information is returned
+ *
+ * @param extra
+ * extra information
+ * @param context
+ * analysis context
+ */
+ @Override
+ public void extra(CellExtra extra, AnalysisContext context) {}
+
/**
* All listeners receive this method when any one Listener does an error report. If an exception is thrown here, the
* entire read will terminate.
diff --git a/src/main/java/com/alibaba/excel/metadata/AbstractCell.java b/src/main/java/com/alibaba/excel/metadata/AbstractCell.java
new file mode 100644
index 0000000..5cea37c
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/metadata/AbstractCell.java
@@ -0,0 +1,33 @@
+package com.alibaba.excel.metadata;
+
+/**
+ * cell
+ *
+ * @author Jiaju Zhuang
+ **/
+public class AbstractCell implements Cell {
+ /**
+ * Row index
+ */
+ private Integer rowIndex;
+ /**
+ * Column index
+ */
+ private Integer columnIndex;
+
+ public Integer getRowIndex() {
+ return rowIndex;
+ }
+
+ public void setRowIndex(Integer rowIndex) {
+ this.rowIndex = rowIndex;
+ }
+
+ public Integer getColumnIndex() {
+ return columnIndex;
+ }
+
+ public void setColumnIndex(Integer columnIndex) {
+ this.columnIndex = columnIndex;
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java b/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java
index 37a1942..6bfd825 100644
--- a/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java
+++ b/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java
@@ -1,6 +1,7 @@
package com.alibaba.excel.metadata;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import com.alibaba.excel.converters.Converter;
@@ -27,7 +28,6 @@ public abstract class AbstractHolder implements ConfigurationHolder {
* Some global variables
*/
private GlobalConfiguration globalConfiguration;
-
/**
*
* Read key:
@@ -58,6 +58,16 @@ public abstract class AbstractHolder implements ConfigurationHolder {
} else {
globalConfiguration.setAutoTrim(basicParameter.getAutoTrim());
}
+
+ if (basicParameter.getLocale() == null) {
+ if (prentAbstractHolder == null) {
+ globalConfiguration.setLocale(Locale.getDefault());
+ } else {
+ globalConfiguration.setLocale(prentAbstractHolder.getGlobalConfiguration().getLocale());
+ }
+ } else {
+ globalConfiguration.setLocale(basicParameter.getLocale());
+ }
}
public Boolean getNewInitialization() {
diff --git a/src/main/java/com/alibaba/excel/metadata/AbstractParameterBuilder.java b/src/main/java/com/alibaba/excel/metadata/AbstractParameterBuilder.java
new file mode 100644
index 0000000..66df25b
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/metadata/AbstractParameterBuilder.java
@@ -0,0 +1,98 @@
+package com.alibaba.excel.metadata;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import com.alibaba.excel.converters.Converter;
+
+/**
+ * ExcelBuilder
+ *
+ * @author Jiaju Zhuang
+ */
+public abstract class AbstractParameterBuilder {
+ /**
+ * You can only choose one of the {@link #head(List)} and {@link #head(Class)}
+ *
+ * @param head
+ * @return
+ */
+ public T head(List> head) {
+ parameter().setHead(head);
+ return self();
+ }
+
+ /**
+ * You can only choose one of the {@link #head(List)} and {@link #head(Class)}
+ *
+ * @param clazz
+ * @return
+ */
+ public T head(Class clazz) {
+ parameter().setClazz(clazz);
+ return self();
+ }
+
+ /**
+ * Custom type conversions override the default.
+ *
+ * @param converter
+ * @return
+ */
+ public T registerConverter(Converter converter) {
+ if (parameter().getCustomConverterList() == null) {
+ parameter().setCustomConverterList(new ArrayList());
+ }
+ parameter().getCustomConverterList().add(converter);
+ return self();
+ }
+
+ /**
+ * true if date uses 1904 windowing, or false if using 1900 date windowing.
+ *
+ * default is false
+ *
+ * @param use1904windowing
+ * @return
+ */
+ public T use1904windowing(Boolean use1904windowing) {
+ parameter().setUse1904windowing(use1904windowing);
+ return self();
+ }
+
+ /**
+ * A Locale
object represents a specific geographical, political, or cultural region. This parameter is
+ * used when formatting dates and numbers.
+ *
+ * @param locale
+ * @return
+ */
+ public T locale(Locale locale) {
+ parameter().setLocale(locale);
+ return self();
+ }
+
+ /**
+ * Automatic trim includes sheet name and content
+ *
+ * @param autoTrim
+ * @return
+ */
+ public T autoTrim(Boolean autoTrim) {
+ parameter().setAutoTrim(autoTrim);
+ return self();
+ }
+
+ @SuppressWarnings("unchecked")
+ protected T self() {
+ return (T)this;
+ }
+
+ /**
+ * Get parameter
+ *
+ * @return
+ */
+ protected abstract C parameter();
+}
diff --git a/src/main/java/com/alibaba/excel/metadata/BasicParameter.java b/src/main/java/com/alibaba/excel/metadata/BasicParameter.java
index 40bffe6..d00c93a 100644
--- a/src/main/java/com/alibaba/excel/metadata/BasicParameter.java
+++ b/src/main/java/com/alibaba/excel/metadata/BasicParameter.java
@@ -1,6 +1,7 @@
package com.alibaba.excel.metadata;
import java.util.List;
+import java.util.Locale;
import com.alibaba.excel.converters.Converter;
@@ -34,6 +35,11 @@ public class BasicParameter {
* @return
*/
private Boolean use1904windowing;
+ /**
+ * A Locale
object represents a specific geographical, political, or cultural region. This parameter is
+ * used when formatting dates and numbers.
+ */
+ private Locale locale;
public List> getHead() {
return head;
@@ -75,4 +81,11 @@ public class BasicParameter {
this.use1904windowing = use1904windowing;
}
+ public Locale getLocale() {
+ return locale;
+ }
+
+ public void setLocale(Locale locale) {
+ this.locale = locale;
+ }
}
diff --git a/src/main/java/com/alibaba/excel/metadata/Cell.java b/src/main/java/com/alibaba/excel/metadata/Cell.java
new file mode 100644
index 0000000..259df7a
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/metadata/Cell.java
@@ -0,0 +1,22 @@
+package com.alibaba.excel.metadata;
+
+/**
+ * Cell
+ *
+ * @author Jiaju Zhuang
+ **/
+public interface Cell {
+ /**
+ * Row index
+ *
+ * @return
+ */
+ Integer getRowIndex();
+
+ /**
+ * Column index
+ *
+ * @return
+ */
+ Integer getColumnIndex();
+}
diff --git a/src/main/java/com/alibaba/excel/metadata/CellData.java b/src/main/java/com/alibaba/excel/metadata/CellData.java
index 7cd5496..2124e10 100644
--- a/src/main/java/com/alibaba/excel/metadata/CellData.java
+++ b/src/main/java/com/alibaba/excel/metadata/CellData.java
@@ -12,7 +12,7 @@ import com.alibaba.excel.util.StringUtils;
*
* @author Jiaju Zhuang
*/
-public class CellData {
+public class CellData extends AbstractCell {
private CellDataTypeEnum type;
/**
* {@link CellDataTypeEnum#NUMBER}
@@ -226,6 +226,42 @@ public class CellData {
}
}
+ public static CellData newEmptyInstance() {
+ return newEmptyInstance(null, null);
+ }
+
+ public static CellData newEmptyInstance(Integer rowIndex, Integer columnIndex) {
+ CellData cellData = new CellData(CellDataTypeEnum.EMPTY);
+ cellData.setRowIndex(rowIndex);
+ cellData.setColumnIndex(columnIndex);
+ return cellData;
+ }
+
+ public static CellData newInstance(Boolean booleanValue) {
+ return newInstance(booleanValue, null, null);
+ }
+
+ public static CellData newInstance(Boolean booleanValue, Integer rowIndex, Integer columnIndex) {
+ CellData cellData = new CellData(booleanValue);
+ cellData.setRowIndex(rowIndex);
+ cellData.setColumnIndex(columnIndex);
+ return cellData;
+ }
+
+ public static CellData newInstance(String stringValue, Integer rowIndex, Integer columnIndex) {
+ CellData cellData = new CellData(stringValue);
+ cellData.setRowIndex(rowIndex);
+ cellData.setColumnIndex(columnIndex);
+ return cellData;
+ }
+
+ public static CellData newInstance(BigDecimal numberValue, Integer rowIndex, Integer columnIndex) {
+ CellData cellData = new CellData(numberValue);
+ cellData.setRowIndex(rowIndex);
+ cellData.setColumnIndex(columnIndex);
+ return cellData;
+ }
+
@Override
public String toString() {
if (type == null) {
diff --git a/src/main/java/com/alibaba/excel/metadata/CellExtra.java b/src/main/java/com/alibaba/excel/metadata/CellExtra.java
new file mode 100644
index 0000000..937b9ac
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/metadata/CellExtra.java
@@ -0,0 +1,121 @@
+package com.alibaba.excel.metadata;
+
+import org.apache.poi.ss.util.CellReference;
+
+import com.alibaba.excel.constant.ExcelXmlConstants;
+import com.alibaba.excel.enums.CellExtraTypeEnum;
+
+/**
+ * Cell extra information.
+ *
+ * @author Jiaju Zhuang
+ */
+public class CellExtra extends AbstractCell {
+ /**
+ * Cell extra type
+ */
+ private CellExtraTypeEnum type;
+ /**
+ * Cell extra data
+ */
+ private String text;
+ /**
+ * First row index,if this object is an interval
+ */
+ private Integer firstRowIndex;
+ /**
+ * Last row index,if this object is an interval
+ */
+ private Integer lastRowIndex;
+ /**
+ * First column index,if this object is an interval
+ */
+ private Integer firstColumnIndex;
+ /**
+ * Last column index,if this object is an interval
+ */
+ private Integer lastColumnIndex;
+
+ public CellExtra(CellExtraTypeEnum type, String text, String range) {
+ super();
+ this.type = type;
+ this.text = text;
+ String[] ranges = range.split(ExcelXmlConstants.CELL_RANGE_SPLIT);
+ CellReference first = new CellReference(ranges[0]);
+ CellReference last = first;
+ this.firstRowIndex = first.getRow();
+ this.firstColumnIndex = (int)first.getCol();
+ setRowIndex(this.firstRowIndex);
+ setColumnIndex(this.firstColumnIndex);
+ if (ranges.length > 1) {
+ last = new CellReference(ranges[1]);
+ }
+ this.lastRowIndex = last.getRow();
+ this.lastColumnIndex = (int)last.getCol();
+ }
+
+ public CellExtra(CellExtraTypeEnum type, String text, Integer rowIndex, Integer columnIndex) {
+ this(type, text, rowIndex, rowIndex, columnIndex, columnIndex);
+ }
+
+ public CellExtra(CellExtraTypeEnum type, String text, Integer firstRowIndex, Integer lastRowIndex,
+ Integer firstColumnIndex, Integer lastColumnIndex) {
+ super();
+ setRowIndex(firstRowIndex);
+ setColumnIndex(firstColumnIndex);
+ this.type = type;
+ this.text = text;
+ this.firstRowIndex = firstRowIndex;
+ this.firstColumnIndex = firstColumnIndex;
+ this.lastRowIndex = lastRowIndex;
+ this.lastColumnIndex = lastColumnIndex;
+ }
+
+ public CellExtraTypeEnum getType() {
+ return type;
+ }
+
+ public void setType(CellExtraTypeEnum type) {
+ this.type = type;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ public Integer getFirstRowIndex() {
+ return firstRowIndex;
+ }
+
+ public void setFirstRowIndex(Integer firstRowIndex) {
+ this.firstRowIndex = firstRowIndex;
+ }
+
+ public Integer getFirstColumnIndex() {
+ return firstColumnIndex;
+ }
+
+ public void setFirstColumnIndex(Integer firstColumnIndex) {
+ this.firstColumnIndex = firstColumnIndex;
+ }
+
+ public Integer getLastRowIndex() {
+ return lastRowIndex;
+ }
+
+ public void setLastRowIndex(Integer lastRowIndex) {
+ this.lastRowIndex = lastRowIndex;
+ }
+
+ public Integer getLastColumnIndex() {
+ return lastColumnIndex;
+ }
+
+ public void setLastColumnIndex(Integer lastColumnIndex) {
+ this.lastColumnIndex = lastColumnIndex;
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/metadata/DataFormatter.java b/src/main/java/com/alibaba/excel/metadata/DataFormatter.java
new file mode 100644
index 0000000..7467cd2
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/metadata/DataFormatter.java
@@ -0,0 +1,786 @@
+/*
+ * ==================================================================== Licensed to the Apache Software Foundation (ASF)
+ * under one or more contributor license agreements. See the NOTICE file distributed with this work for additional
+ * information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ * 2012 - Alfresco Software, Ltd. Alfresco Software has modified source of this file The details of changes as svn diff
+ * can be found in svn at location root/projects/3rd-party/src
+ * ====================================================================
+ */
+package com.alibaba.excel.metadata;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.text.DateFormatSymbols;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.ParsePosition;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.poi.ss.usermodel.DateUtil;
+import org.apache.poi.ss.usermodel.ExcelGeneralNumberFormat;
+import org.apache.poi.ss.usermodel.ExcelStyleDateFormatter;
+import org.apache.poi.ss.usermodel.FractionFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.alibaba.excel.util.DateUtils;
+
+/**
+ * Written with reference to {@link org.apache.poi.ss.usermodel.DataFormatter}.Made some optimizations for date
+ * conversion.
+ *
+ * This is a non-thread-safe class.
+ *
+ * @author Jiaju Zhuang
+ */
+public class DataFormatter {
+ /** For logging any problems we find */
+ private static final Logger LOGGER = LoggerFactory.getLogger(DataFormatter.class);
+ private static final String defaultFractionWholePartFormat = "#";
+ private static final String defaultFractionFractionPartFormat = "#/##";
+ /** Pattern to find a number format: "0" or "#" */
+ private static final Pattern numPattern = Pattern.compile("[0#]+");
+
+ /** Pattern to find days of week as text "ddd...." */
+ private static final Pattern daysAsText = Pattern.compile("([d]{3,})", Pattern.CASE_INSENSITIVE);
+
+ /** Pattern to find "AM/PM" marker */
+ private static final Pattern amPmPattern =
+ Pattern.compile("(([AP])[M/P]*)|(([上下])[午/下]*)", Pattern.CASE_INSENSITIVE);
+
+ /** Pattern to find formats with condition ranges e.g. [>=100] */
+ private static final Pattern rangeConditionalPattern =
+ Pattern.compile(".*\\[\\s*(>|>=|<|<=|=)\\s*[0-9]*\\.*[0-9].*");
+
+ /**
+ * A regex to find locale patterns like [$$-1009] and [$?-452]. Note that we don't currently process these into
+ * locales
+ */
+ private static final Pattern localePatternGroup = Pattern.compile("(\\[\\$[^-\\]]*-[0-9A-Z]+])");
+
+ /**
+ * A regex to match the colour formattings rules. Allowed colours are: Black, Blue, Cyan, Green, Magenta, Red,
+ * White, Yellow, "Color n" (1<=n<=56)
+ */
+ private static final Pattern colorPattern = Pattern.compile(
+ "(\\[BLACK])|(\\[BLUE])|(\\[CYAN])|(\\[GREEN])|" + "(\\[MAGENTA])|(\\[RED])|(\\[WHITE])|(\\[YELLOW])|"
+ + "(\\[COLOR\\s*\\d])|(\\[COLOR\\s*[0-5]\\d])|(\\[DBNum(1|2|3)])|(\\[\\$-\\d{0,3}])",
+ Pattern.CASE_INSENSITIVE);
+
+ /**
+ * A regex to identify a fraction pattern. This requires that replaceAll("\\?", "#") has already been called
+ */
+ private static final Pattern fractionPattern = Pattern.compile("(?:([#\\d]+)\\s+)?(#+)\\s*/\\s*([#\\d]+)");
+
+ /**
+ * A regex to strip junk out of fraction formats
+ */
+ private static final Pattern fractionStripper = Pattern.compile("(\"[^\"]*\")|([^ ?#\\d/]+)");
+
+ /**
+ * A regex to detect if an alternate grouping character is used in a numeric format
+ */
+ private static final Pattern alternateGrouping = Pattern.compile("([#0]([^.#0])[#0]{3})");
+
+ /**
+ * Cells formatted with a date or time format and which contain invalid date or time values show 255 pound signs
+ * ("#").
+ */
+ private static final String invalidDateTimeString;
+ static {
+ StringBuilder buf = new StringBuilder();
+ for (int i = 0; i < 255; i++)
+ buf.append('#');
+ invalidDateTimeString = buf.toString();
+ }
+
+ /**
+ * The decimal symbols of the locale used for formatting values.
+ */
+ private DecimalFormatSymbols decimalSymbols;
+
+ /**
+ * The date symbols of the locale used for formatting values.
+ */
+ private DateFormatSymbols dateSymbols;
+ /** A default format to use when a number pattern cannot be parsed. */
+ private Format defaultNumFormat;
+ /**
+ * A map to cache formats. Map formats
+ */
+ private final Map formats = new HashMap();
+
+ /** stores the locale valid it the last formatting call */
+ private Locale locale;
+ /**
+ * true if date uses 1904 windowing, or false if using 1900 date windowing.
+ *
+ * default is false
+ *
+ * @return
+ */
+ private Boolean use1904windowing;
+
+ /**
+ * Creates a formatter using the {@link Locale#getDefault() default locale}.
+ */
+ public DataFormatter() {
+ this(null, null);
+ }
+
+ /**
+ * Creates a formatter using the given locale.
+ *
+ */
+ public DataFormatter(Locale locale, Boolean use1904windowing) {
+ this.use1904windowing = use1904windowing != null ? use1904windowing : Boolean.FALSE;
+ this.locale = locale != null ? locale : Locale.getDefault();
+ this.dateSymbols = DateFormatSymbols.getInstance(this.locale);
+ this.decimalSymbols = DecimalFormatSymbols.getInstance(this.locale);
+ }
+
+ private Format getFormat(Integer dataFormat, String dataFormatString) {
+ // See if we already have it cached
+ Format format = formats.get(dataFormatString);
+ if (format != null) {
+ return format;
+ }
+ // Is it one of the special built in types, General or @?
+ if ("General".equalsIgnoreCase(dataFormatString) || "@".equals(dataFormatString)) {
+ format = getDefaultFormat();
+ addFormat(dataFormatString, format);
+ return format;
+ }
+
+ // Build a formatter, and cache it
+ format = createFormat(dataFormat, dataFormatString);
+ addFormat(dataFormatString, format);
+ return format;
+ }
+
+ private Format createFormat(Integer dataFormat, String dataFormatString) {
+ String formatStr = dataFormatString;
+
+ Format format = checkSpecialConverter(formatStr);
+ if (format != null) {
+ return format;
+ }
+
+ // Remove colour formatting if present
+ Matcher colourM = colorPattern.matcher(formatStr);
+ while (colourM.find()) {
+ String colour = colourM.group();
+
+ // Paranoid replacement...
+ int at = formatStr.indexOf(colour);
+ if (at == -1)
+ break;
+ String nFormatStr = formatStr.substring(0, at) + formatStr.substring(at + colour.length());
+ if (nFormatStr.equals(formatStr))
+ break;
+
+ // Try again in case there's multiple
+ formatStr = nFormatStr;
+ colourM = colorPattern.matcher(formatStr);
+ }
+
+ // Strip off the locale information, we use an instance-wide locale for everything
+ Matcher m = localePatternGroup.matcher(formatStr);
+ while (m.find()) {
+ String match = m.group();
+ String symbol = match.substring(match.indexOf('$') + 1, match.indexOf('-'));
+ if (symbol.indexOf('$') > -1) {
+ symbol = symbol.substring(0, symbol.indexOf('$')) + '\\' + symbol.substring(symbol.indexOf('$'));
+ }
+ formatStr = m.replaceAll(symbol);
+ m = localePatternGroup.matcher(formatStr);
+ }
+
+ // Check for special cases
+ if (formatStr == null || formatStr.trim().length() == 0) {
+ return getDefaultFormat();
+ }
+
+ if ("General".equalsIgnoreCase(formatStr) || "@".equals(formatStr)) {
+ return getDefaultFormat();
+ }
+
+ if (DateUtils.isADateFormat(dataFormat, formatStr)) {
+ return createDateFormat(formatStr);
+ }
+ // Excel supports fractions in format strings, which Java doesn't
+ if (formatStr.contains("#/") || formatStr.contains("?/")) {
+ String[] chunks = formatStr.split(";");
+ for (String chunk1 : chunks) {
+ String chunk = chunk1.replaceAll("\\?", "#");
+ Matcher matcher = fractionStripper.matcher(chunk);
+ chunk = matcher.replaceAll(" ");
+ chunk = chunk.replaceAll(" +", " ");
+ Matcher fractionMatcher = fractionPattern.matcher(chunk);
+ // take the first match
+ if (fractionMatcher.find()) {
+ String wholePart = (fractionMatcher.group(1) == null) ? "" : defaultFractionWholePartFormat;
+ return new FractionFormat(wholePart, fractionMatcher.group(3));
+ }
+ }
+
+ // Strip custom text in quotes and escaped characters for now as it can cause performance problems in
+ // fractions.
+ // String strippedFormatStr = formatStr.replaceAll("\\\\ ", " ").replaceAll("\\\\.",
+ // "").replaceAll("\"[^\"]*\"", " ").replaceAll("\\?", "#");
+ return new FractionFormat(defaultFractionWholePartFormat, defaultFractionFractionPartFormat);
+ }
+
+ if (numPattern.matcher(formatStr).find()) {
+ return createNumberFormat(formatStr);
+ }
+ return getDefaultFormat();
+ }
+
+ private Format checkSpecialConverter(String dataFormatString) {
+ if ("00000\\-0000".equals(dataFormatString) || "00000-0000".equals(dataFormatString)) {
+ return new ZipPlusFourFormat();
+ }
+ if ("[<=9999999]###\\-####;\\(###\\)\\ ###\\-####".equals(dataFormatString)
+ || "[<=9999999]###-####;(###) ###-####".equals(dataFormatString)
+ || "###\\-####;\\(###\\)\\ ###\\-####".equals(dataFormatString)
+ || "###-####;(###) ###-####".equals(dataFormatString)) {
+ return new PhoneFormat();
+ }
+ if ("000\\-00\\-0000".equals(dataFormatString) || "000-00-0000".equals(dataFormatString)) {
+ return new SSNFormat();
+ }
+ return null;
+ }
+
+ private Format createDateFormat(String pFormatStr) {
+ String formatStr = pFormatStr;
+ formatStr = formatStr.replaceAll("\\\\-", "-");
+ formatStr = formatStr.replaceAll("\\\\,", ",");
+ formatStr = formatStr.replaceAll("\\\\\\.", "."); // . is a special regexp char
+ formatStr = formatStr.replaceAll("\\\\ ", " ");
+ formatStr = formatStr.replaceAll("\\\\/", "/"); // weird: m\\/d\\/yyyy
+ formatStr = formatStr.replaceAll(";@", "");
+ formatStr = formatStr.replaceAll("\"/\"", "/"); // "/" is escaped for no reason in: mm"/"dd"/"yyyy
+ formatStr = formatStr.replace("\"\"", "'"); // replace Excel quoting with Java style quoting
+ formatStr = formatStr.replaceAll("\\\\T", "'T'"); // Quote the T is iso8601 style dates
+ formatStr = formatStr.replace("\"", "");
+
+ boolean hasAmPm = false;
+ Matcher amPmMatcher = amPmPattern.matcher(formatStr);
+ while (amPmMatcher.find()) {
+ formatStr = amPmMatcher.replaceAll("@");
+ hasAmPm = true;
+ amPmMatcher = amPmPattern.matcher(formatStr);
+ }
+ formatStr = formatStr.replaceAll("@", "a");
+
+ Matcher dateMatcher = daysAsText.matcher(formatStr);
+ if (dateMatcher.find()) {
+ String match = dateMatcher.group(0).toUpperCase(Locale.ROOT).replaceAll("D", "E");
+ formatStr = dateMatcher.replaceAll(match);
+ }
+
+ // Convert excel date format to SimpleDateFormat.
+ // Excel uses lower and upper case 'm' for both minutes and months.
+ // From Excel help:
+ /*
+ The "m" or "mm" code must appear immediately after the "h" or"hh"
+ code or immediately before the "ss" code; otherwise, Microsoft
+ Excel displays the month instead of minutes."
+ */
+ StringBuilder sb = new StringBuilder();
+ char[] chars = formatStr.toCharArray();
+ boolean mIsMonth = true;
+ List ms = new ArrayList();
+ boolean isElapsed = false;
+ for (int j = 0; j < chars.length; j++) {
+ char c = chars[j];
+ if (c == '\'') {
+ sb.append(c);
+ j++;
+
+ // skip until the next quote
+ while (j < chars.length) {
+ c = chars[j];
+ sb.append(c);
+ if (c == '\'') {
+ break;
+ }
+ j++;
+ }
+ } else if (c == '[' && !isElapsed) {
+ isElapsed = true;
+ mIsMonth = false;
+ sb.append(c);
+ } else if (c == ']' && isElapsed) {
+ isElapsed = false;
+ sb.append(c);
+ } else if (isElapsed) {
+ if (c == 'h' || c == 'H') {
+ sb.append('H');
+ } else if (c == 'm' || c == 'M') {
+ sb.append('m');
+ } else if (c == 's' || c == 'S') {
+ sb.append('s');
+ } else {
+ sb.append(c);
+ }
+ } else if (c == 'h' || c == 'H') {
+ mIsMonth = false;
+ if (hasAmPm) {
+ sb.append('h');
+ } else {
+ sb.append('H');
+ }
+ } else if (c == 'm' || c == 'M') {
+ if (mIsMonth) {
+ sb.append('M');
+ ms.add(Integer.valueOf(sb.length() - 1));
+ } else {
+ sb.append('m');
+ }
+ } else if (c == 's' || c == 'S') {
+ sb.append('s');
+ // if 'M' precedes 's' it should be minutes ('m')
+ for (int index : ms) {
+ if (sb.charAt(index) == 'M') {
+ sb.replace(index, index + 1, "m");
+ }
+ }
+ mIsMonth = true;
+ ms.clear();
+ } else if (Character.isLetter(c)) {
+ mIsMonth = true;
+ ms.clear();
+ if (c == 'y' || c == 'Y') {
+ sb.append('y');
+ } else if (c == 'd' || c == 'D') {
+ sb.append('d');
+ } else {
+ sb.append(c);
+ }
+ } else {
+ if (Character.isWhitespace(c)) {
+ ms.clear();
+ }
+ sb.append(c);
+ }
+ }
+ formatStr = sb.toString();
+
+ try {
+ return new ExcelStyleDateFormatter(formatStr, dateSymbols);
+ } catch (IllegalArgumentException iae) {
+ LOGGER.debug("Formatting failed for format {}, falling back", formatStr, iae);
+ // the pattern could not be parsed correctly,
+ // so fall back to the default number format
+ return getDefaultFormat();
+ }
+
+ }
+
+ private String cleanFormatForNumber(String formatStr) {
+ StringBuilder sb = new StringBuilder(formatStr);
+ // If they requested spacers, with "_",
+ // remove those as we don't do spacing
+ // If they requested full-column-width
+ // padding, with "*", remove those too
+ for (int i = 0; i < sb.length(); i++) {
+ char c = sb.charAt(i);
+ if (c == '_' || c == '*') {
+ if (i > 0 && sb.charAt((i - 1)) == '\\') {
+ // It's escaped, don't worry
+ continue;
+ }
+ if (i < sb.length() - 1) {
+ // Remove the character we're supposed
+ // to match the space of / pad to the
+ // column width with
+ sb.deleteCharAt(i + 1);
+ }
+ // Remove the _ too
+ sb.deleteCharAt(i);
+ i--;
+ }
+ }
+
+ // Now, handle the other aspects like
+ // quoting and scientific notation
+ for (int i = 0; i < sb.length(); i++) {
+ char c = sb.charAt(i);
+ // remove quotes and back slashes
+ if (c == '\\' || c == '"') {
+ sb.deleteCharAt(i);
+ i--;
+
+ // for scientific/engineering notation
+ } else if (c == '+' && i > 0 && sb.charAt(i - 1) == 'E') {
+ sb.deleteCharAt(i);
+ i--;
+ }
+ }
+
+ return sb.toString();
+ }
+
+ private static class InternalDecimalFormatWithScale extends Format {
+
+ private static final Pattern endsWithCommas = Pattern.compile("(,+)$");
+ private BigDecimal divider;
+ private static final BigDecimal ONE_THOUSAND = new BigDecimal(1000);
+ private final DecimalFormat df;
+
+ private static String trimTrailingCommas(String s) {
+ return s.replaceAll(",+$", "");
+ }
+
+ public InternalDecimalFormatWithScale(String pattern, DecimalFormatSymbols symbols) {
+ df = new DecimalFormat(trimTrailingCommas(pattern), symbols);
+ setExcelStyleRoundingMode(df);
+ Matcher endsWithCommasMatcher = endsWithCommas.matcher(pattern);
+ if (endsWithCommasMatcher.find()) {
+ String commas = (endsWithCommasMatcher.group(1));
+ BigDecimal temp = BigDecimal.ONE;
+ for (int i = 0; i < commas.length(); ++i) {
+ temp = temp.multiply(ONE_THOUSAND);
+ }
+ divider = temp;
+ } else {
+ divider = null;
+ }
+ }
+
+ private Object scaleInput(Object obj) {
+ if (divider != null) {
+ if (obj instanceof BigDecimal) {
+ obj = ((BigDecimal)obj).divide(divider, RoundingMode.HALF_UP);
+ } else if (obj instanceof Double) {
+ obj = (Double)obj / divider.doubleValue();
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+ return obj;
+ }
+
+ @Override
+ public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
+ obj = scaleInput(obj);
+ return df.format(obj, toAppendTo, pos);
+ }
+
+ @Override
+ public Object parseObject(String source, ParsePosition pos) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private Format createNumberFormat(String formatStr) {
+ String format = cleanFormatForNumber(formatStr);
+ DecimalFormatSymbols symbols = decimalSymbols;
+
+ // Do we need to change the grouping character?
+ // eg for a format like #'##0 which wants 12'345 not 12,345
+ Matcher agm = alternateGrouping.matcher(format);
+ if (agm.find()) {
+ char grouping = agm.group(2).charAt(0);
+ // Only replace the grouping character if it is not the default
+ // grouping character for the US locale (',') in order to enable
+ // correct grouping for non-US locales.
+ if (grouping != ',') {
+ symbols = DecimalFormatSymbols.getInstance(locale);
+
+ symbols.setGroupingSeparator(grouping);
+ String oldPart = agm.group(1);
+ String newPart = oldPart.replace(grouping, ',');
+ format = format.replace(oldPart, newPart);
+ }
+ }
+
+ try {
+ return new InternalDecimalFormatWithScale(format, symbols);
+ } catch (IllegalArgumentException iae) {
+ LOGGER.debug("Formatting failed for format {}, falling back", formatStr, iae);
+ // the pattern could not be parsed correctly,
+ // so fall back to the default number format
+ return getDefaultFormat();
+ }
+ }
+
+ private Format getDefaultFormat() {
+ // for numeric cells try user supplied default
+ if (defaultNumFormat != null) {
+ return defaultNumFormat;
+ // otherwise use general format
+ }
+ defaultNumFormat = new ExcelGeneralNumberFormat(locale);
+ return defaultNumFormat;
+ }
+
+ /**
+ * Performs Excel-style date formatting, using the supplied Date and format
+ */
+ private String performDateFormatting(Date d, Format dateFormat) {
+ Format df = dateFormat != null ? dateFormat : getDefaultFormat();
+ return df.format(d);
+ }
+
+ /**
+ * Returns the formatted value of an Excel date as a String based on the cell's DataFormat
.
+ * i.e. "Thursday, January 02, 2003" , "01/02/2003" , "02-Jan" , etc.
+ *
+ * If any conditional format rules apply, the highest priority with a number format is used. If no rules contain a
+ * number format, or no rules apply, the cell's style format is used. If the style does not have a format, the
+ * default date format is applied.
+ *
+ * @param data
+ * to format
+ * @param dataFormat
+ * @param dataFormatString
+ * @return Formatted value
+ */
+ private String getFormattedDateString(Double data, Integer dataFormat, String dataFormatString) {
+ Format dateFormat = getFormat(dataFormat, dataFormatString);
+ if (dateFormat instanceof ExcelStyleDateFormatter) {
+ // Hint about the raw excel value
+ ((ExcelStyleDateFormatter)dateFormat).setDateToBeFormatted(data);
+ }
+ return performDateFormatting(DateUtil.getJavaDate(data, use1904windowing), dateFormat);
+ }
+
+ /**
+ * Returns the formatted value of an Excel number as a String based on the cell's DataFormat
.
+ * Supported formats include currency, percents, decimals, phone number, SSN, etc.: "61.54%", "$100.00", "(800)
+ * 555-1234".
+ *
+ * Format comes from either the highest priority conditional format rule with a specified format, or from the cell
+ * style.
+ *
+ * @param data
+ * to format
+ * @param dataFormat
+ * @param dataFormatString
+ * @return a formatted number string
+ */
+ private String getFormattedNumberString(Double data, Integer dataFormat, String dataFormatString) {
+ Format numberFormat = getFormat(dataFormat, dataFormatString);
+ String formatted = numberFormat.format(data);
+ return formatted.replaceFirst("E(\\d)", "E+$1"); // to match Excel's E-notation
+ }
+
+ /**
+ * Format data.
+ *
+ * @param data
+ * @param dataFormat
+ * @param dataFormatString
+ * @return
+ */
+ public String format(Double data, Integer dataFormat, String dataFormatString) {
+ if (DateUtils.isADateFormat(dataFormat, dataFormatString)) {
+ return getFormattedDateString(data, dataFormat, dataFormatString);
+ }
+ return getFormattedNumberString(data, dataFormat, dataFormatString);
+ }
+
+ /**
+ *
+ * Sets a default number format to be used when the Excel format cannot be parsed successfully. Note: This is
+ * a fall back for when an error occurs while parsing an Excel number format pattern. This will not affect cells
+ * with the General format.
+ *
+ *
+ * The value that will be passed to the Format's format method (specified by java.text.Format#format
)
+ * will be a double value from a numeric cell. Therefore the code in the format method should expect a
+ * Number
value.
+ *
+ *
+ * @param format
+ * A Format instance to be used as a default
+ * @see Format#format
+ */
+ public void setDefaultNumberFormat(Format format) {
+ for (Map.Entry entry : formats.entrySet()) {
+ if (entry.getValue() == defaultNumFormat) {
+ entry.setValue(format);
+ }
+ }
+ defaultNumFormat = format;
+ }
+
+ /**
+ * Adds a new format to the available formats.
+ *
+ * The value that will be passed to the Format's format method (specified by java.text.Format#format
)
+ * will be a double value from a numeric cell. Therefore the code in the format method should expect a
+ * Number
value.
+ *
+ *
+ * @param excelFormatStr
+ * The data format string
+ * @param format
+ * A Format instance
+ */
+ public void addFormat(String excelFormatStr, Format format) {
+ formats.put(excelFormatStr, format);
+ }
+
+ // Some custom formats
+
+ /**
+ * @return a DecimalFormat with parseIntegerOnly set true
+ */
+ private static DecimalFormat createIntegerOnlyFormat(String fmt) {
+ DecimalFormatSymbols dsf = DecimalFormatSymbols.getInstance(Locale.ROOT);
+ DecimalFormat result = new DecimalFormat(fmt, dsf);
+ result.setParseIntegerOnly(true);
+ return result;
+ }
+
+ /**
+ * Enables excel style rounding mode (round half up) on the Decimal Format given.
+ */
+ public static void setExcelStyleRoundingMode(DecimalFormat format) {
+ setExcelStyleRoundingMode(format, RoundingMode.HALF_UP);
+ }
+
+ /**
+ * Enables custom rounding mode on the given Decimal Format.
+ *
+ * @param format
+ * DecimalFormat
+ * @param roundingMode
+ * RoundingMode
+ */
+ public static void setExcelStyleRoundingMode(DecimalFormat format, RoundingMode roundingMode) {
+ format.setRoundingMode(roundingMode);
+ }
+
+ /**
+ * Format class for Excel's SSN format. This class mimics Excel's built-in SSN formatting.
+ *
+ * @author James May
+ */
+ @SuppressWarnings("serial")
+ private static final class SSNFormat extends Format {
+ private static final DecimalFormat df = createIntegerOnlyFormat("000000000");
+
+ private SSNFormat() {
+ // enforce singleton
+ }
+
+ /** Format a number as an SSN */
+ public static String format(Number num) {
+ String result = df.format(num);
+ return result.substring(0, 3) + '-' + result.substring(3, 5) + '-' + result.substring(5, 9);
+ }
+
+ @Override
+ public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
+ return toAppendTo.append(format((Number)obj));
+ }
+
+ @Override
+ public Object parseObject(String source, ParsePosition pos) {
+ return df.parseObject(source, pos);
+ }
+ }
+
+ /**
+ * Format class for Excel Zip + 4 format. This class mimics Excel's built-in formatting for Zip + 4.
+ *
+ * @author James May
+ */
+ @SuppressWarnings("serial")
+ private static final class ZipPlusFourFormat extends Format {
+ private static final DecimalFormat df = createIntegerOnlyFormat("000000000");
+
+ private ZipPlusFourFormat() {
+ // enforce singleton
+ }
+
+ /** Format a number as Zip + 4 */
+ public static String format(Number num) {
+ String result = df.format(num);
+ return result.substring(0, 5) + '-' + result.substring(5, 9);
+ }
+
+ @Override
+ public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
+ return toAppendTo.append(format((Number)obj));
+ }
+
+ @Override
+ public Object parseObject(String source, ParsePosition pos) {
+ return df.parseObject(source, pos);
+ }
+ }
+
+ /**
+ * Format class for Excel phone number format. This class mimics Excel's built-in phone number formatting.
+ *
+ * @author James May
+ */
+ @SuppressWarnings("serial")
+ private static final class PhoneFormat extends Format {
+ private static final DecimalFormat df = createIntegerOnlyFormat("##########");
+
+ private PhoneFormat() {
+ // enforce singleton
+ }
+
+ /** Format a number as a phone number */
+ public static String format(Number num) {
+ String result = df.format(num);
+ StringBuilder sb = new StringBuilder();
+ String seg1, seg2, seg3;
+ int len = result.length();
+ if (len <= 4) {
+ return result;
+ }
+
+ seg3 = result.substring(len - 4, len);
+ seg2 = result.substring(Math.max(0, len - 7), len - 4);
+ seg1 = result.substring(Math.max(0, len - 10), Math.max(0, len - 7));
+
+ if (seg1.trim().length() > 0) {
+ sb.append('(').append(seg1).append(") ");
+ }
+ if (seg2.trim().length() > 0) {
+ sb.append(seg2).append('-');
+ }
+ sb.append(seg3);
+ return sb.toString();
+ }
+
+ @Override
+ public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
+ return toAppendTo.append(format((Number)obj));
+ }
+
+ @Override
+ public Object parseObject(String source, ParsePosition pos) {
+ return df.parseObject(source, pos);
+ }
+ }
+
+}
diff --git a/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java b/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java
index 921d70a..12cc8d3 100644
--- a/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java
+++ b/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java
@@ -1,5 +1,7 @@
package com.alibaba.excel.metadata;
+import java.util.Locale;
+
/**
* Global configuration
*
@@ -18,6 +20,11 @@ public class GlobalConfiguration {
* @return
*/
private Boolean use1904windowing;
+ /**
+ * A Locale
object represents a specific geographical, political, or cultural region. This parameter is
+ * used when formatting dates and numbers.
+ */
+ private Locale locale;
public Boolean getUse1904windowing() {
return use1904windowing;
@@ -34,4 +41,12 @@ public class GlobalConfiguration {
public void setAutoTrim(Boolean autoTrim) {
this.autoTrim = autoTrim;
}
+
+ public Locale getLocale() {
+ return locale;
+ }
+
+ public void setLocale(Locale locale) {
+ this.locale = locale;
+ }
}
diff --git a/src/main/java/com/alibaba/excel/metadata/Head.java b/src/main/java/com/alibaba/excel/metadata/Head.java
index c1cea10..c578cbb 100644
--- a/src/main/java/com/alibaba/excel/metadata/Head.java
+++ b/src/main/java/com/alibaba/excel/metadata/Head.java
@@ -4,6 +4,9 @@ import java.util.ArrayList;
import java.util.List;
import com.alibaba.excel.metadata.property.ColumnWidthProperty;
+import com.alibaba.excel.metadata.property.FontProperty;
+import com.alibaba.excel.metadata.property.LoopMergeProperty;
+import com.alibaba.excel.metadata.property.StyleProperty;
/**
* excel head
@@ -35,6 +38,26 @@ public class Head {
* column with
*/
private ColumnWidthProperty columnWidthProperty;
+ /**
+ * Loop merge
+ */
+ private LoopMergeProperty loopMergeProperty;
+ /**
+ * Head style
+ */
+ private StyleProperty headStyleProperty;
+ /**
+ * Content style
+ */
+ private StyleProperty contentStyleProperty;
+ /**
+ * Head font
+ */
+ private FontProperty headFontProperty;
+ /**
+ * Content font
+ */
+ private FontProperty contentFontProperty;
public Head(Integer columnIndex, String fieldName, List headNameList, Boolean forceIndex,
Boolean forceName) {
@@ -95,4 +118,44 @@ public class Head {
public void setForceName(Boolean forceName) {
this.forceName = forceName;
}
+
+ public LoopMergeProperty getLoopMergeProperty() {
+ return loopMergeProperty;
+ }
+
+ public void setLoopMergeProperty(LoopMergeProperty loopMergeProperty) {
+ this.loopMergeProperty = loopMergeProperty;
+ }
+
+ public StyleProperty getHeadStyleProperty() {
+ return headStyleProperty;
+ }
+
+ public void setHeadStyleProperty(StyleProperty headStyleProperty) {
+ this.headStyleProperty = headStyleProperty;
+ }
+
+ public StyleProperty getContentStyleProperty() {
+ return contentStyleProperty;
+ }
+
+ public void setContentStyleProperty(StyleProperty contentStyleProperty) {
+ this.contentStyleProperty = contentStyleProperty;
+ }
+
+ public FontProperty getHeadFontProperty() {
+ return headFontProperty;
+ }
+
+ public void setHeadFontProperty(FontProperty headFontProperty) {
+ this.headFontProperty = headFontProperty;
+ }
+
+ public FontProperty getContentFontProperty() {
+ return contentFontProperty;
+ }
+
+ public void setContentFontProperty(FontProperty contentFontProperty) {
+ this.contentFontProperty = contentFontProperty;
+ }
}
diff --git a/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java b/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java
index 782f635..34109ad 100644
--- a/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java
+++ b/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java
@@ -1,7 +1,6 @@
package com.alibaba.excel.metadata.property;
import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -12,8 +11,6 @@ import java.util.TreeMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.alibaba.excel.annotation.ExcelIgnore;
-import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.format.NumberFormat;
@@ -21,7 +18,6 @@ import com.alibaba.excel.converters.AutoConverter;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.HeadKindEnum;
import com.alibaba.excel.exception.ExcelCommonException;
-import com.alibaba.excel.exception.ExcelGenerateException;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.Holder;
import com.alibaba.excel.util.ClassUtils;
@@ -86,10 +82,10 @@ public class ExcelHeadProperty {
headIndex++;
}
headKind = HeadKindEnum.STRING;
- } else {
- // convert headClazz to head
- initColumnProperties(holder, convertAllFiled);
}
+ // convert headClazz to head
+ initColumnProperties(holder, convertAllFiled);
+
initHeadRowNumber();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("The initialization sheet/table 'ExcelHeadProperty' is complete , head kind is {}", headKind);
@@ -163,10 +159,14 @@ public class ExcelHeadProperty {
List tmpHeadList = new ArrayList();
boolean notForceName = excelProperty == null || excelProperty.value().length <= 0
|| (excelProperty.value().length == 1 && StringUtils.isEmpty((excelProperty.value())[0]));
- if (notForceName) {
- tmpHeadList.add(field.getName());
+ if (headMap.containsKey(index)) {
+ tmpHeadList.addAll(headMap.get(index).getHeadNameList());
} else {
- Collections.addAll(tmpHeadList, excelProperty.value());
+ if (notForceName) {
+ tmpHeadList.add(field.getName());
+ } else {
+ Collections.addAll(tmpHeadList, excelProperty.value());
+ }
}
Head head = new Head(index, field.getName(), tmpHeadList, forceIndex, !notForceName);
ExcelContentProperty excelContentProperty = new ExcelContentProperty();
diff --git a/src/main/java/com/alibaba/excel/metadata/property/FontProperty.java b/src/main/java/com/alibaba/excel/metadata/property/FontProperty.java
new file mode 100644
index 0000000..04caf9b
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/metadata/property/FontProperty.java
@@ -0,0 +1,180 @@
+package com.alibaba.excel.metadata.property;
+
+import org.apache.poi.common.usermodel.fonts.FontCharset;
+import org.apache.poi.hssf.usermodel.HSSFPalette;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+import com.alibaba.excel.annotation.write.style.ContentFontStyle;
+import com.alibaba.excel.annotation.write.style.HeadFontStyle;
+
+/**
+ * Configuration from annotations
+ *
+ * @author Jiaju Zhuang
+ */
+public class FontProperty {
+ /**
+ * The name for the font (i.e. Arial)
+ */
+ private String fontName;
+ /**
+ * Height in the familiar unit of measure - points
+ */
+ private Short fontHeightInPoints;
+ /**
+ * Whether to use italics or not
+ */
+ private Boolean italic;
+ /**
+ * Whether to use a strikeout horizontal line through the text or not
+ */
+ private Boolean strikeout;
+ /**
+ * The color for the font
+ *
+ * @see Font#COLOR_NORMAL
+ * @see Font#COLOR_RED
+ * @see HSSFPalette#getColor(short)
+ * @see IndexedColors
+ */
+ private Short color;
+ /**
+ * Set normal,super or subscript.
+ *
+ * @see Font#SS_NONE
+ * @see Font#SS_SUPER
+ * @see Font#SS_SUB
+ */
+ private Short typeOffset;
+ /**
+ * set type of text underlining to use
+ *
+ * @see Font#U_NONE
+ * @see Font#U_SINGLE
+ * @see Font#U_DOUBLE
+ * @see Font#U_SINGLE_ACCOUNTING
+ * @see Font#U_DOUBLE_ACCOUNTING
+ */
+
+ private Byte underline;
+ /**
+ * Set character-set to use.
+ *
+ * @see FontCharset
+ * @see Font#ANSI_CHARSET
+ * @see Font#DEFAULT_CHARSET
+ * @see Font#SYMBOL_CHARSET
+ */
+ private Integer charset;
+ /**
+ * Bold
+ */
+ private Boolean bold;
+
+ public static FontProperty build(HeadFontStyle headFontStyle) {
+ if (headFontStyle == null) {
+ return null;
+ }
+ FontProperty styleProperty = new FontProperty();
+ styleProperty.setFontName(headFontStyle.fontName());
+ styleProperty.setFontHeightInPoints(headFontStyle.fontHeightInPoints());
+ styleProperty.setItalic(headFontStyle.italic());
+ styleProperty.setStrikeout(headFontStyle.strikeout());
+ styleProperty.setColor(headFontStyle.color());
+ styleProperty.setTypeOffset(headFontStyle.typeOffset());
+ styleProperty.setUnderline(headFontStyle.underline());
+ styleProperty.setCharset(headFontStyle.charset());
+ styleProperty.setBold(headFontStyle.bold());
+ return styleProperty;
+ }
+
+ public static FontProperty build(ContentFontStyle contentFontStyle) {
+ if (contentFontStyle == null) {
+ return null;
+ }
+ FontProperty styleProperty = new FontProperty();
+ styleProperty.setFontName(contentFontStyle.fontName());
+ styleProperty.setFontHeightInPoints(contentFontStyle.fontHeightInPoints());
+ styleProperty.setItalic(contentFontStyle.italic());
+ styleProperty.setStrikeout(contentFontStyle.strikeout());
+ styleProperty.setColor(contentFontStyle.color());
+ styleProperty.setTypeOffset(contentFontStyle.typeOffset());
+ styleProperty.setUnderline(contentFontStyle.underline());
+ styleProperty.setCharset(contentFontStyle.charset());
+ styleProperty.setBold(contentFontStyle.bold());
+ return styleProperty;
+ }
+
+ public String getFontName() {
+ return fontName;
+ }
+
+ public void setFontName(String fontName) {
+ this.fontName = fontName;
+ }
+
+ public Short getFontHeightInPoints() {
+ return fontHeightInPoints;
+ }
+
+ public void setFontHeightInPoints(Short fontHeightInPoints) {
+ this.fontHeightInPoints = fontHeightInPoints;
+ }
+
+ public Boolean getItalic() {
+ return italic;
+ }
+
+ public void setItalic(Boolean italic) {
+ this.italic = italic;
+ }
+
+ public Boolean getStrikeout() {
+ return strikeout;
+ }
+
+ public void setStrikeout(Boolean strikeout) {
+ this.strikeout = strikeout;
+ }
+
+ public Short getColor() {
+ return color;
+ }
+
+ public void setColor(Short color) {
+ this.color = color;
+ }
+
+ public Short getTypeOffset() {
+ return typeOffset;
+ }
+
+ public void setTypeOffset(Short typeOffset) {
+ this.typeOffset = typeOffset;
+ }
+
+ public Byte getUnderline() {
+ return underline;
+ }
+
+ public void setUnderline(Byte underline) {
+ this.underline = underline;
+ }
+
+ public Integer getCharset() {
+ return charset;
+ }
+
+ public void setCharset(Integer charset) {
+ this.charset = charset;
+ }
+
+ public Boolean getBold() {
+ return bold;
+ }
+
+ public void setBold(Boolean bold) {
+ this.bold = bold;
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/metadata/property/LoopMergeProperty.java b/src/main/java/com/alibaba/excel/metadata/property/LoopMergeProperty.java
new file mode 100644
index 0000000..05084bf
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/metadata/property/LoopMergeProperty.java
@@ -0,0 +1,47 @@
+package com.alibaba.excel.metadata.property;
+
+import com.alibaba.excel.annotation.write.style.ContentLoopMerge;
+
+/**
+ * Configuration from annotations
+ *
+ * @author Jiaju Zhuang
+ */
+public class LoopMergeProperty {
+ /**
+ * Each row
+ */
+ private int eachRow;
+ /**
+ * Extend column
+ */
+ private int columnExtend;
+
+ public LoopMergeProperty(int eachRow, int columnExtend) {
+ this.eachRow = eachRow;
+ this.columnExtend = columnExtend;
+ }
+
+ public static LoopMergeProperty build(ContentLoopMerge contentLoopMerge) {
+ if (contentLoopMerge == null) {
+ return null;
+ }
+ return new LoopMergeProperty(contentLoopMerge.eachRow(), contentLoopMerge.columnExtend());
+ }
+
+ public int getEachRow() {
+ return eachRow;
+ }
+
+ public void setEachRow(int eachRow) {
+ this.eachRow = eachRow;
+ }
+
+ public int getColumnExtend() {
+ return columnExtend;
+ }
+
+ public void setColumnExtend(int columnExtend) {
+ this.columnExtend = columnExtend;
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/metadata/property/OnceAbsoluteMergeProperty.java b/src/main/java/com/alibaba/excel/metadata/property/OnceAbsoluteMergeProperty.java
new file mode 100644
index 0000000..c509219
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/metadata/property/OnceAbsoluteMergeProperty.java
@@ -0,0 +1,74 @@
+package com.alibaba.excel.metadata.property;
+
+import com.alibaba.excel.annotation.write.style.OnceAbsoluteMerge;
+
+/**
+ * Configuration from annotations
+ *
+ * @author Jiaju Zhuang
+ */
+public class OnceAbsoluteMergeProperty {
+ /**
+ * First row
+ */
+ private int firstRowIndex;
+ /**
+ * Last row
+ */
+ private int lastRowIndex;
+ /**
+ * First column
+ */
+ private int firstColumnIndex;
+ /**
+ * Last row
+ */
+ private int lastColumnIndex;
+
+ public OnceAbsoluteMergeProperty(int firstRowIndex, int lastRowIndex, int firstColumnIndex, int lastColumnIndex) {
+ this.firstRowIndex = firstRowIndex;
+ this.lastRowIndex = lastRowIndex;
+ this.firstColumnIndex = firstColumnIndex;
+ this.lastColumnIndex = lastColumnIndex;
+ }
+
+ public static OnceAbsoluteMergeProperty build(OnceAbsoluteMerge onceAbsoluteMerge) {
+ if (onceAbsoluteMerge == null) {
+ return null;
+ }
+ return new OnceAbsoluteMergeProperty(onceAbsoluteMerge.firstRowIndex(), onceAbsoluteMerge.lastRowIndex(),
+ onceAbsoluteMerge.firstColumnIndex(), onceAbsoluteMerge.lastColumnIndex());
+ }
+
+ public int getFirstRowIndex() {
+ return firstRowIndex;
+ }
+
+ public void setFirstRowIndex(int firstRowIndex) {
+ this.firstRowIndex = firstRowIndex;
+ }
+
+ public int getLastRowIndex() {
+ return lastRowIndex;
+ }
+
+ public void setLastRowIndex(int lastRowIndex) {
+ this.lastRowIndex = lastRowIndex;
+ }
+
+ public int getFirstColumnIndex() {
+ return firstColumnIndex;
+ }
+
+ public void setFirstColumnIndex(int firstColumnIndex) {
+ this.firstColumnIndex = firstColumnIndex;
+ }
+
+ public int getLastColumnIndex() {
+ return lastColumnIndex;
+ }
+
+ public void setLastColumnIndex(int lastColumnIndex) {
+ this.lastColumnIndex = lastColumnIndex;
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/metadata/property/StyleProperty.java b/src/main/java/com/alibaba/excel/metadata/property/StyleProperty.java
new file mode 100644
index 0000000..9222b10
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/metadata/property/StyleProperty.java
@@ -0,0 +1,377 @@
+package com.alibaba.excel.metadata.property;
+
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.BuiltinFormats;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IgnoredErrorType;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+
+import com.alibaba.excel.annotation.write.style.ContentStyle;
+import com.alibaba.excel.annotation.write.style.HeadStyle;
+import com.alibaba.excel.write.metadata.style.WriteFont;
+
+/**
+ * Configuration from annotations
+ *
+ * @author Jiaju Zhuang
+ */
+public class StyleProperty {
+ /**
+ * Set the data format (must be a valid format). Built in formats are defined at {@link BuiltinFormats}.
+ */
+ private Short dataFormat;
+ /**
+ * Set the font for this style
+ */
+ private WriteFont writeFont;
+ /**
+ * Set the cell's using this style to be hidden
+ */
+ private Boolean hidden;
+
+ /**
+ * Set the cell's using this style to be locked
+ */
+ private Boolean locked;
+ /**
+ * Turn on or off "Quote Prefix" or "123 Prefix" for the style, which is used to tell Excel that the thing which
+ * looks like a number or a formula shouldn't be treated as on. Turning this on is somewhat (but not completely, see
+ * {@link IgnoredErrorType}) like prefixing the cell value with a ' in Excel
+ */
+ private Boolean quotePrefix;
+ /**
+ * Set the type of horizontal alignment for the cell
+ */
+ private HorizontalAlignment horizontalAlignment;
+ /**
+ * Set whether the text should be wrapped. Setting this flag to true
make all content visible within a
+ * cell by displaying it on multiple lines
+ *
+ */
+ private Boolean wrapped;
+ /**
+ * Set the type of vertical alignment for the cell
+ */
+ private VerticalAlignment verticalAlignment;
+ /**
+ * Set the degree of rotation for the text in the cell.
+ *
+ * Note: HSSF uses values from -90 to 90 degrees, whereas XSSF uses values from 0 to 180 degrees. The
+ * implementations of this method will map between these two value-ranges accordingly, however the corresponding
+ * getter is returning values in the range mandated by the current type of Excel file-format that this CellStyle is
+ * applied to.
+ */
+ private Short rotation;
+ /**
+ * Set the number of spaces to indent the text in the cell
+ */
+ private Short indent;
+ /**
+ * Set the type of border to use for the left border of the cell
+ */
+ private BorderStyle borderLeft;
+ /**
+ * Set the type of border to use for the right border of the cell
+ */
+ private BorderStyle borderRight;
+ /**
+ * Set the type of border to use for the top border of the cell
+ */
+ private BorderStyle borderTop;
+
+ /**
+ * Set the type of border to use for the bottom border of the cell
+ */
+ private BorderStyle borderBottom;
+ /**
+ * Set the color to use for the left border
+ *
+ * @see IndexedColors
+ */
+ private Short leftBorderColor;
+
+ /**
+ * Set the color to use for the right border
+ *
+ * @see IndexedColors
+ *
+ */
+ private Short rightBorderColor;
+
+ /**
+ * Set the color to use for the top border
+ *
+ * @see IndexedColors
+ *
+ */
+ private Short topBorderColor;
+ /**
+ * Set the color to use for the bottom border
+ *
+ * @see IndexedColors
+ *
+ */
+ private Short bottomBorderColor;
+ /**
+ * Setting to one fills the cell with the foreground color... No idea about other values
+ *
+ * @see FillPatternType#SOLID_FOREGROUND
+ */
+ private FillPatternType fillPatternType;
+
+ /**
+ * Set the background fill color.
+ *
+ * @see IndexedColors
+ *
+ */
+ private Short fillBackgroundColor;
+
+ /**
+ * Set the foreground fill color Note: Ensure Foreground color is set prior to background color.
+ *
+ * @see IndexedColors
+ *
+ */
+ private Short fillForegroundColor;
+ /**
+ * Controls if the Cell should be auto-sized to shrink to fit if the text is too long
+ */
+ private Boolean shrinkToFit;
+
+ public static StyleProperty build(HeadStyle headStyle) {
+ if (headStyle == null) {
+ return null;
+ }
+ StyleProperty styleProperty = new StyleProperty();
+ styleProperty.setDataFormat(headStyle.dataFormat());
+ styleProperty.setHidden(headStyle.hidden());
+ styleProperty.setLocked(headStyle.locked());
+ styleProperty.setQuotePrefix(headStyle.quotePrefix());
+ styleProperty.setHorizontalAlignment(headStyle.horizontalAlignment());
+ styleProperty.setWrapped(headStyle.wrapped());
+ styleProperty.setVerticalAlignment(headStyle.verticalAlignment());
+ styleProperty.setRotation(headStyle.rotation());
+ styleProperty.setIndent(headStyle.indent());
+ styleProperty.setBorderLeft(headStyle.borderLeft());
+ styleProperty.setBorderRight(headStyle.borderRight());
+ styleProperty.setBorderTop(headStyle.borderTop());
+ styleProperty.setBorderBottom(headStyle.borderBottom());
+ styleProperty.setLeftBorderColor(headStyle.leftBorderColor());
+ styleProperty.setRightBorderColor(headStyle.rightBorderColor());
+ styleProperty.setTopBorderColor(headStyle.topBorderColor());
+ styleProperty.setBottomBorderColor(headStyle.bottomBorderColor());
+ styleProperty.setFillPatternType(headStyle.fillPatternType());
+ styleProperty.setFillBackgroundColor(headStyle.fillBackgroundColor());
+ styleProperty.setFillForegroundColor(headStyle.fillForegroundColor());
+ styleProperty.setShrinkToFit(headStyle.shrinkToFit());
+ return styleProperty;
+ }
+
+ public static StyleProperty build(ContentStyle contentStyle) {
+ if (contentStyle == null) {
+ return null;
+ }
+ StyleProperty styleProperty = new StyleProperty();
+ styleProperty.setDataFormat(contentStyle.dataFormat());
+ styleProperty.setHidden(contentStyle.hidden());
+ styleProperty.setLocked(contentStyle.locked());
+ styleProperty.setQuotePrefix(contentStyle.quotePrefix());
+ styleProperty.setHorizontalAlignment(contentStyle.horizontalAlignment());
+ styleProperty.setWrapped(contentStyle.wrapped());
+ styleProperty.setVerticalAlignment(contentStyle.verticalAlignment());
+ styleProperty.setRotation(contentStyle.rotation());
+ styleProperty.setIndent(contentStyle.indent());
+ styleProperty.setBorderLeft(contentStyle.borderLeft());
+ styleProperty.setBorderRight(contentStyle.borderRight());
+ styleProperty.setBorderTop(contentStyle.borderTop());
+ styleProperty.setBorderBottom(contentStyle.borderBottom());
+ styleProperty.setLeftBorderColor(contentStyle.leftBorderColor());
+ styleProperty.setRightBorderColor(contentStyle.rightBorderColor());
+ styleProperty.setTopBorderColor(contentStyle.topBorderColor());
+ styleProperty.setBottomBorderColor(contentStyle.bottomBorderColor());
+ styleProperty.setFillPatternType(contentStyle.fillPatternType());
+ styleProperty.setFillBackgroundColor(contentStyle.fillBackgroundColor());
+ styleProperty.setFillForegroundColor(contentStyle.fillForegroundColor());
+ styleProperty.setShrinkToFit(contentStyle.shrinkToFit());
+ return styleProperty;
+ }
+
+ public Short getDataFormat() {
+ return dataFormat;
+ }
+
+ public void setDataFormat(Short dataFormat) {
+ this.dataFormat = dataFormat;
+ }
+
+ public WriteFont getWriteFont() {
+ return writeFont;
+ }
+
+ public void setWriteFont(WriteFont writeFont) {
+ this.writeFont = writeFont;
+ }
+
+ public Boolean getHidden() {
+ return hidden;
+ }
+
+ public void setHidden(Boolean hidden) {
+ this.hidden = hidden;
+ }
+
+ public Boolean getLocked() {
+ return locked;
+ }
+
+ public void setLocked(Boolean locked) {
+ this.locked = locked;
+ }
+
+ public Boolean getQuotePrefix() {
+ return quotePrefix;
+ }
+
+ public void setQuotePrefix(Boolean quotePrefix) {
+ this.quotePrefix = quotePrefix;
+ }
+
+ public HorizontalAlignment getHorizontalAlignment() {
+ return horizontalAlignment;
+ }
+
+ public void setHorizontalAlignment(HorizontalAlignment horizontalAlignment) {
+ this.horizontalAlignment = horizontalAlignment;
+ }
+
+ public Boolean getWrapped() {
+ return wrapped;
+ }
+
+ public void setWrapped(Boolean wrapped) {
+ this.wrapped = wrapped;
+ }
+
+ public VerticalAlignment getVerticalAlignment() {
+ return verticalAlignment;
+ }
+
+ public void setVerticalAlignment(VerticalAlignment verticalAlignment) {
+ this.verticalAlignment = verticalAlignment;
+ }
+
+ public Short getRotation() {
+ return rotation;
+ }
+
+ public void setRotation(Short rotation) {
+ this.rotation = rotation;
+ }
+
+ public Short getIndent() {
+ return indent;
+ }
+
+ public void setIndent(Short indent) {
+ this.indent = indent;
+ }
+
+ public BorderStyle getBorderLeft() {
+ return borderLeft;
+ }
+
+ public void setBorderLeft(BorderStyle borderLeft) {
+ this.borderLeft = borderLeft;
+ }
+
+ public BorderStyle getBorderRight() {
+ return borderRight;
+ }
+
+ public void setBorderRight(BorderStyle borderRight) {
+ this.borderRight = borderRight;
+ }
+
+ public BorderStyle getBorderTop() {
+ return borderTop;
+ }
+
+ public void setBorderTop(BorderStyle borderTop) {
+ this.borderTop = borderTop;
+ }
+
+ public BorderStyle getBorderBottom() {
+ return borderBottom;
+ }
+
+ public void setBorderBottom(BorderStyle borderBottom) {
+ this.borderBottom = borderBottom;
+ }
+
+ public Short getLeftBorderColor() {
+ return leftBorderColor;
+ }
+
+ public void setLeftBorderColor(Short leftBorderColor) {
+ this.leftBorderColor = leftBorderColor;
+ }
+
+ public Short getRightBorderColor() {
+ return rightBorderColor;
+ }
+
+ public void setRightBorderColor(Short rightBorderColor) {
+ this.rightBorderColor = rightBorderColor;
+ }
+
+ public Short getTopBorderColor() {
+ return topBorderColor;
+ }
+
+ public void setTopBorderColor(Short topBorderColor) {
+ this.topBorderColor = topBorderColor;
+ }
+
+ public Short getBottomBorderColor() {
+ return bottomBorderColor;
+ }
+
+ public void setBottomBorderColor(Short bottomBorderColor) {
+ this.bottomBorderColor = bottomBorderColor;
+ }
+
+ public FillPatternType getFillPatternType() {
+ return fillPatternType;
+ }
+
+ public void setFillPatternType(FillPatternType fillPatternType) {
+ this.fillPatternType = fillPatternType;
+ }
+
+ public Short getFillBackgroundColor() {
+ return fillBackgroundColor;
+ }
+
+ public void setFillBackgroundColor(Short fillBackgroundColor) {
+ this.fillBackgroundColor = fillBackgroundColor;
+ }
+
+ public Short getFillForegroundColor() {
+ return fillForegroundColor;
+ }
+
+ public void setFillForegroundColor(Short fillForegroundColor) {
+ this.fillForegroundColor = fillForegroundColor;
+ }
+
+ public Boolean getShrinkToFit() {
+ return shrinkToFit;
+ }
+
+ public void setShrinkToFit(Boolean shrinkToFit) {
+ this.shrinkToFit = shrinkToFit;
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/read/builder/AbstractExcelReaderParameterBuilder.java b/src/main/java/com/alibaba/excel/read/builder/AbstractExcelReaderParameterBuilder.java
new file mode 100644
index 0000000..4e5e370
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/read/builder/AbstractExcelReaderParameterBuilder.java
@@ -0,0 +1,47 @@
+package com.alibaba.excel.read.builder;
+
+import java.util.ArrayList;
+
+import com.alibaba.excel.metadata.AbstractParameterBuilder;
+import com.alibaba.excel.read.listener.ReadListener;
+import com.alibaba.excel.read.metadata.ReadBasicParameter;
+
+/**
+ * Build ExcelBuilder
+ *
+ * @author Jiaju Zhuang
+ */
+public abstract class AbstractExcelReaderParameterBuilder extends AbstractParameterBuilder {
+ /**
+ * Count the number of added heads when read sheet.
+ *
+ *
+ * 0 - This Sheet has no head ,since the first row are the data
+ *
+ * 1 - This Sheet has one row head , this is the default
+ *
+ * 2 - This Sheet has two row head ,since the third row is the data
+ *
+ * @param headRowNumber
+ * @return
+ */
+ public T headRowNumber(Integer headRowNumber) {
+ parameter().setHeadRowNumber(headRowNumber);
+ return self();
+ }
+
+ /**
+ * Custom type listener run after default
+ *
+ * @param readListener
+ * @return
+ */
+ public T registerReadListener(ReadListener readListener) {
+ if (parameter().getCustomReadListenerList() == null) {
+ parameter().setCustomReadListenerList(new ArrayList());
+ }
+ parameter().getCustomReadListenerList().add(readListener);
+ return self();
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java
index 0c63726..81f3586 100644
--- a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java
+++ b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java
@@ -2,7 +2,7 @@ package com.alibaba.excel.read.builder;
import java.io.File;
import java.io.InputStream;
-import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import javax.xml.parsers.SAXParserFactory;
@@ -11,10 +11,10 @@ import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.cache.ReadCache;
import com.alibaba.excel.cache.selector.ReadCacheSelector;
import com.alibaba.excel.context.AnalysisContext;
-import com.alibaba.excel.converters.Converter;
+import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.event.AnalysisEventListener;
+import com.alibaba.excel.event.SyncReadListener;
import com.alibaba.excel.read.listener.ModelBuildEventListener;
-import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.read.metadata.ReadWorkbook;
import com.alibaba.excel.support.ExcelTypeEnum;
@@ -23,7 +23,7 @@ import com.alibaba.excel.support.ExcelTypeEnum;
*
* @author Jiaju Zhuang
*/
-public class ExcelReaderBuilder {
+public class ExcelReaderBuilder extends AbstractExcelReaderParameterBuilder {
/**
* Workbook
*/
@@ -133,98 +133,6 @@ public class ExcelReaderBuilder {
return this;
}
- /**
- * Count the number of added heads when read sheet.
- *
- *
- * 0 - This Sheet has no head ,since the first row are the data
- *
- * 1 - This Sheet has one row head , this is the default
- *
- * 2 - This Sheet has two row head ,since the third row is the data
- *
- * @param headRowNumber
- * @return
- */
- public ExcelReaderBuilder headRowNumber(Integer headRowNumber) {
- readWorkbook.setHeadRowNumber(headRowNumber);
- return this;
- }
-
- /**
- * You can only choose one of the {@link ExcelReaderBuilder#head(List)} and {@link ExcelReaderBuilder#head(Class)}
- *
- * @param head
- * @return
- */
- public ExcelReaderBuilder head(List> head) {
- readWorkbook.setHead(head);
- return this;
- }
-
- /**
- * You can only choose one of the {@link ExcelReaderBuilder#head(List)} and {@link ExcelReaderBuilder#head(Class)}
- *
- * @param clazz
- * @return
- */
- public ExcelReaderBuilder head(Class clazz) {
- readWorkbook.setClazz(clazz);
- return this;
- }
-
- /**
- * Custom type conversions override the default.
- *
- * @param converter
- * @return
- */
- public ExcelReaderBuilder registerConverter(Converter converter) {
- if (readWorkbook.getCustomConverterList() == null) {
- readWorkbook.setCustomConverterList(new ArrayList());
- }
- readWorkbook.getCustomConverterList().add(converter);
- return this;
- }
-
- /**
- * Custom type listener run after default
- *
- * @param readListener
- * @return
- */
- public ExcelReaderBuilder registerReadListener(ReadListener readListener) {
- if (readWorkbook.getCustomReadListenerList() == null) {
- readWorkbook.setCustomReadListenerList(new ArrayList());
- }
- readWorkbook.getCustomReadListenerList().add(readListener);
- return this;
- }
-
- /**
- * true if date uses 1904 windowing, or false if using 1900 date windowing.
- *
- * default is false
- *
- * @param use1904windowing
- * @return
- */
- public ExcelReaderBuilder use1904windowing(Boolean use1904windowing) {
- readWorkbook.setUse1904windowing(use1904windowing);
- return this;
- }
-
- /**
- * Automatic trim includes sheet name and content
- *
- * @param autoTrim
- * @return
- */
- public ExcelReaderBuilder autoTrim(Boolean autoTrim) {
- readWorkbook.setAutoTrim(autoTrim);
- return this;
- }
-
/**
* Whether the encryption
*
@@ -253,6 +161,21 @@ public class ExcelReaderBuilder {
return this;
}
+ /**
+ * Read some extra information, not by default
+ *
+ * @param extraType
+ * extra information type
+ * @return
+ */
+ public ExcelReaderBuilder extraRead(CellExtraTypeEnum extraType) {
+ if (readWorkbook.getExtraReadSet() == null) {
+ readWorkbook.setExtraReadSet(new HashSet());
+ }
+ readWorkbook.getExtraReadSet().add(extraType);
+ return this;
+ }
+
/**
* Whether to use the default listener, which is used by default.
*
@@ -270,11 +193,24 @@ public class ExcelReaderBuilder {
return new ExcelReader(readWorkbook);
}
- public ExcelReader doReadAll() {
+ public void doReadAll() {
+ ExcelReader excelReader = build();
+ excelReader.readAll();
+ excelReader.finish();
+ }
+
+ /**
+ * Synchronous reads return results
+ *
+ * @return
+ */
+ public List doReadAllSync() {
+ SyncReadListener syncReadListener = new SyncReadListener();
+ registerReadListener(syncReadListener);
ExcelReader excelReader = build();
excelReader.readAll();
excelReader.finish();
- return excelReader;
+ return (List)syncReadListener.getList();
}
public ExcelReaderSheetBuilder sheet() {
@@ -299,4 +235,9 @@ public class ExcelReaderBuilder {
}
return excelReaderSheetBuilder;
}
+
+ @Override
+ protected ReadWorkbook parameter() {
+ return readWorkbook;
+ }
}
diff --git a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java
index d494e23..84ec6ba 100644
--- a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java
+++ b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java
@@ -1,14 +1,11 @@
package com.alibaba.excel.read.builder;
-import java.util.ArrayList;
import java.util.List;
import com.alibaba.excel.ExcelReader;
-import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.event.SyncReadListener;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelGenerateException;
-import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.read.metadata.ReadSheet;
/**
@@ -16,7 +13,7 @@ import com.alibaba.excel.read.metadata.ReadSheet;
*
* @author Jiaju Zhuang
*/
-public class ExcelReaderSheetBuilder {
+public class ExcelReaderSheetBuilder extends AbstractExcelReaderParameterBuilder {
private ExcelReader excelReader;
/**
* Sheet
@@ -54,98 +51,6 @@ public class ExcelReaderSheetBuilder {
return this;
}
- /**
- * Count the number of added heads when read sheet.
- *
- *
- * 0 - This Sheet has no head ,since the first row are the data
- *
- * 1 - This Sheet has one row head , this is the default
- *
- * 2 - This Sheet has two row head ,since the third row is the data
- *
- * @param headRowNumber
- * @return
- */
- public ExcelReaderSheetBuilder headRowNumber(Integer headRowNumber) {
- readSheet.setHeadRowNumber(headRowNumber);
- return this;
- }
-
- /**
- * You can only choose one of the {@link ExcelReaderBuilder#head(List)} and {@link ExcelReaderBuilder#head(Class)}
- *
- * @param head
- * @return
- */
- public ExcelReaderSheetBuilder head(List> head) {
- readSheet.setHead(head);
- return this;
- }
-
- /**
- * You can only choose one of the {@link ExcelReaderBuilder#head(List)} and {@link ExcelReaderBuilder#head(Class)}
- *
- * @param clazz
- * @return
- */
- public ExcelReaderSheetBuilder head(Class clazz) {
- readSheet.setClazz(clazz);
- return this;
- }
-
- /**
- * Custom type conversions override the default.
- *
- * @param converter
- * @return
- */
- public ExcelReaderSheetBuilder registerConverter(Converter converter) {
- if (readSheet.getCustomConverterList() == null) {
- readSheet.setCustomConverterList(new ArrayList());
- }
- readSheet.getCustomConverterList().add(converter);
- return this;
- }
-
- /**
- * Custom type listener run after default
- *
- * @param readListener
- * @return
- */
- public ExcelReaderSheetBuilder registerReadListener(ReadListener readListener) {
- if (readSheet.getCustomReadListenerList() == null) {
- readSheet.setCustomReadListenerList(new ArrayList());
- }
- readSheet.getCustomReadListenerList().add(readListener);
- return this;
- }
-
- /**
- * true if date uses 1904 windowing, or false if using 1900 date windowing.
- *
- * default is false
- *
- * @param use1904windowing
- * @return
- */
- public ExcelReaderSheetBuilder use1904windowing(Boolean use1904windowing) {
- readSheet.setUse1904windowing(use1904windowing);
- return this;
- }
-
- /**
- * Automatic trim includes sheet name and content
- *
- * @param autoTrim
- * @return
- */
- public ExcelReaderSheetBuilder autoTrim(Boolean autoTrim) {
- readSheet.setAutoTrim(autoTrim);
- return this;
- }
-
public ReadSheet build() {
return readSheet;
}
@@ -177,4 +82,8 @@ public class ExcelReaderSheetBuilder {
return (List)syncReadListener.getList();
}
+ @Override
+ protected ReadSheet parameter() {
+ return readSheet;
+ }
}
diff --git a/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java b/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java
index f5594db..78b57e0 100644
--- a/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java
+++ b/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java
@@ -62,6 +62,11 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener
(String)ConverterUtils.convertToJavaObject(cellData, null, null, currentReadHolder.converterMap(),
currentReadHolder.globalConfiguration(), context.readRowHolder().getRowIndex(), key));
}
+ int headSize = currentReadHolder.excelReadHeadProperty().getHeadMap().size();
+ while (index < headSize) {
+ map.put(index, null);
+ index++;
+ }
return map;
} else {
// Compatible with the old code the old code returns a list
@@ -82,6 +87,11 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener
(String)ConverterUtils.convertToJavaObject(cellData, null, null, currentReadHolder.converterMap(),
currentReadHolder.globalConfiguration(), context.readRowHolder().getRowIndex(), key));
}
+ int headSize = currentReadHolder.excelReadHeadProperty().getHeadMap().size();
+ while (index < headSize) {
+ list.add(null);
+ index++;
+ }
return list;
}
}
diff --git a/src/main/java/com/alibaba/excel/read/listener/ReadListener.java b/src/main/java/com/alibaba/excel/read/listener/ReadListener.java
index 142c531..f1d341f 100644
--- a/src/main/java/com/alibaba/excel/read/listener/ReadListener.java
+++ b/src/main/java/com/alibaba/excel/read/listener/ReadListener.java
@@ -5,6 +5,7 @@ import java.util.Map;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.Listener;
import com.alibaba.excel.metadata.CellData;
+import com.alibaba.excel.metadata.CellExtra;
/**
* Interface to listen for read results
@@ -40,6 +41,16 @@ public interface ReadListener extends Listener {
*/
void invoke(T data, AnalysisContext context);
+ /**
+ * The current method is called when extra information is returned
+ *
+ * @param extra
+ * extra information
+ * @param context
+ * analysis context
+ */
+ void extra(CellExtra extra, AnalysisContext context);
+
/**
* if have something to do after all analysis
*
diff --git a/src/main/java/com/alibaba/excel/read/listener/ReadListenerRegistryCenter.java b/src/main/java/com/alibaba/excel/read/listener/ReadListenerRegistryCenter.java
deleted file mode 100644
index 07bc68c..0000000
--- a/src/main/java/com/alibaba/excel/read/listener/ReadListenerRegistryCenter.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.alibaba.excel.read.listener;
-
-import com.alibaba.excel.context.AnalysisContext;
-import com.alibaba.excel.event.AnalysisEventListener;
-import com.alibaba.excel.read.listener.event.AnalysisFinishEvent;
-
-/**
- * Registry center.
- *
- * @author jipengfei
- */
-public interface ReadListenerRegistryCenter {
-
- /**
- * register
- *
- * @param listener
- * Analysis listener
- */
- void register(AnalysisEventListener listener);
-
- /**
- * Parse one row to notify all event listeners
- *
- * @param event
- * parse event
- * @param analysisContext
- * Analysis context
- */
- void notifyEndOneRow(AnalysisFinishEvent event, AnalysisContext analysisContext);
-
- /**
- * Notify after all analysed
- *
- * @param analysisContext
- * Analysis context
- */
- void notifyAfterAllAnalysed(AnalysisContext analysisContext);
-}
diff --git a/src/main/java/com/alibaba/excel/read/listener/event/AnalysisFinishEvent.java b/src/main/java/com/alibaba/excel/read/listener/event/AnalysisFinishEvent.java
deleted file mode 100644
index 9749cf0..0000000
--- a/src/main/java/com/alibaba/excel/read/listener/event/AnalysisFinishEvent.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.alibaba.excel.read.listener.event;
-
-import java.util.Map;
-
-import com.alibaba.excel.metadata.CellData;
-
-/**
- *
- * Event
- *
- * @author jipengfei
- */
-public interface AnalysisFinishEvent {
- /**
- * Get result
- *
- * @return
- */
- Map getAnalysisResult();
-}
diff --git a/src/main/java/com/alibaba/excel/read/listener/event/EachRowAnalysisFinishEvent.java b/src/main/java/com/alibaba/excel/read/listener/event/EachRowAnalysisFinishEvent.java
deleted file mode 100644
index 879a59a..0000000
--- a/src/main/java/com/alibaba/excel/read/listener/event/EachRowAnalysisFinishEvent.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.alibaba.excel.read.listener.event;
-
-import java.util.Map;
-
-import com.alibaba.excel.metadata.CellData;
-
-/**
- * @author jipengfei
- */
-public class EachRowAnalysisFinishEvent implements AnalysisFinishEvent {
- private Map result;
-
- public EachRowAnalysisFinishEvent(Map content) {
- this.result = content;
- }
-
- @Override
- public Map getAnalysisResult() {
- return result;
- }
-}
diff --git a/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java b/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java
index 7ddab56..c9e4db9 100644
--- a/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java
+++ b/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java
@@ -2,12 +2,14 @@ package com.alibaba.excel.read.metadata;
import java.io.File;
import java.io.InputStream;
+import java.util.Set;
import javax.xml.parsers.SAXParserFactory;
import com.alibaba.excel.cache.ReadCache;
import com.alibaba.excel.cache.selector.ReadCacheSelector;
import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.listener.ModelBuildEventListener;
import com.alibaba.excel.support.ExcelTypeEnum;
@@ -83,6 +85,12 @@ public class ReadWorkbook extends ReadBasicParameter {
* The {@link ModelBuildEventListener} is loaded by default to convert the object.
*/
private Boolean useDefaultListener;
+ /**
+ * Read some additional fields. None are read by default.
+ *
+ * @see CellExtraTypeEnum
+ */
+ private Set extraReadSet;
/**
* The default is all excel objects.Default is true.
*
@@ -212,4 +220,12 @@ public class ReadWorkbook extends ReadBasicParameter {
public void setUseDefaultListener(Boolean useDefaultListener) {
this.useDefaultListener = useDefaultListener;
}
+
+ public Set getExtraReadSet() {
+ return extraReadSet;
+ }
+
+ public void setExtraReadSet(Set extraReadSet) {
+ this.extraReadSet = extraReadSet;
+ }
}
diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java
index 7133f99..a0bf7f1 100644
--- a/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java
+++ b/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java
@@ -3,41 +3,27 @@ package com.alibaba.excel.read.metadata.holder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ConverterKeyBuild;
import com.alibaba.excel.converters.DefaultConverterLoader;
-import com.alibaba.excel.enums.HeadKindEnum;
import com.alibaba.excel.enums.HolderEnum;
-import com.alibaba.excel.event.AnalysisEventListener;
-import com.alibaba.excel.exception.ExcelAnalysisException;
-import com.alibaba.excel.exception.ExcelAnalysisStopException;
import com.alibaba.excel.metadata.AbstractHolder;
-import com.alibaba.excel.metadata.CellData;
-import com.alibaba.excel.metadata.Head;
-import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.read.listener.ModelBuildEventListener;
import com.alibaba.excel.read.listener.ReadListener;
-import com.alibaba.excel.read.listener.ReadListenerRegistryCenter;
-import com.alibaba.excel.read.listener.event.AnalysisFinishEvent;
import com.alibaba.excel.read.metadata.ReadBasicParameter;
import com.alibaba.excel.read.metadata.ReadWorkbook;
import com.alibaba.excel.read.metadata.property.ExcelReadHeadProperty;
-import com.alibaba.excel.util.CollectionUtils;
-import com.alibaba.excel.util.ConverterUtils;
-import com.alibaba.excel.util.StringUtils;
/**
* Read Holder
*
* @author Jiaju Zhuang
*/
-public abstract class AbstractReadHolder extends AbstractHolder implements ReadHolder, ReadListenerRegistryCenter {
+public abstract class AbstractReadHolder extends AbstractHolder implements ReadHolder {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractReadHolder.class);
/**
@@ -117,123 +103,6 @@ public abstract class AbstractReadHolder extends AbstractHolder implements ReadH
}
}
- @Override
- public void register(AnalysisEventListener listener) {
- readListenerList.add(listener);
- }
-
- @Override
- public void notifyEndOneRow(AnalysisFinishEvent event, AnalysisContext analysisContext) {
- Map cellDataMap = event.getAnalysisResult();
- if (CollectionUtils.isEmpty(cellDataMap)) {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.warn("Empty row!");
- }
- if (analysisContext.readWorkbookHolder().getIgnoreEmptyRow()) {
- return;
- }
- }
- ReadRowHolder readRowHolder = analysisContext.readRowHolder();
- readRowHolder.setCurrentRowAnalysisResult(cellDataMap);
- int rowIndex = readRowHolder.getRowIndex();
- int currentheadRowNumber = analysisContext.readSheetHolder().getHeadRowNumber();
-
- if (rowIndex >= currentheadRowNumber) {
- // Now is data
- for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) {
- try {
- readListener.invoke(readRowHolder.getCurrentRowAnalysisResult(), analysisContext);
- } catch (Exception e) {
- for (ReadListener readListenerException : analysisContext.currentReadHolder().readListenerList()) {
- try {
- readListenerException.onException(e, analysisContext);
- } catch (Exception exception) {
- throw new ExcelAnalysisException(exception.getMessage(), exception);
- }
- }
- break;
- }
- if (!readListener.hasNext(analysisContext)) {
- throw new ExcelAnalysisStopException();
- }
- }
- } else {
- // Last head column
- if (currentheadRowNumber == rowIndex + 1) {
- buildHead(analysisContext, cellDataMap);
- }
- // Now is header
- for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) {
- try {
- readListener.invokeHead(cellDataMap, analysisContext);
- } catch (Exception e) {
- for (ReadListener readListenerException : analysisContext.currentReadHolder().readListenerList()) {
- try {
- readListenerException.onException(e, analysisContext);
- } catch (Exception exception) {
- throw new ExcelAnalysisException(exception.getMessage(), exception);
- }
- }
- break;
- }
- if (!readListener.hasNext(analysisContext)) {
- throw new ExcelAnalysisStopException();
- }
- }
- }
- }
-
- @Override
- public void notifyAfterAllAnalysed(AnalysisContext analysisContext) {
- for (ReadListener readListener : readListenerList) {
- readListener.doAfterAllAnalysed(analysisContext);
- }
- }
-
- private void buildHead(AnalysisContext analysisContext, Map cellDataMap) {
- if (!HeadKindEnum.CLASS.equals(analysisContext.currentReadHolder().excelReadHeadProperty().getHeadKind())) {
- return;
- }
- Map dataMap = ConverterUtils.convertToStringMap(cellDataMap, analysisContext);
- ExcelReadHeadProperty excelHeadPropertyData = analysisContext.readSheetHolder().excelReadHeadProperty();
- Map headMapData = excelHeadPropertyData.getHeadMap();
- Map contentPropertyMapData = excelHeadPropertyData.getContentPropertyMap();
- Map tmpHeadMap = new HashMap(headMapData.size() * 4 / 3 + 1);
- Map tmpContentPropertyMap =
- new HashMap(contentPropertyMapData.size() * 4 / 3 + 1);
- for (Map.Entry entry : headMapData.entrySet()) {
- Head headData = entry.getValue();
- if (headData.getForceIndex() || !headData.getForceName()) {
- tmpHeadMap.put(entry.getKey(), headData);
- tmpContentPropertyMap.put(entry.getKey(), contentPropertyMapData.get(entry.getKey()));
- continue;
- }
- List headNameList = headData.getHeadNameList();
- String headName = headNameList.get(headNameList.size() - 1);
- for (Map.Entry stringEntry : dataMap.entrySet()) {
- if (stringEntry == null) {
- continue;
- }
- String headString = stringEntry.getValue();
- Integer stringKey = stringEntry.getKey();
- if (StringUtils.isEmpty(headString)) {
- continue;
- }
- if (analysisContext.currentReadHolder().globalConfiguration().getAutoTrim()) {
- headString = headString.trim();
- }
- if (headName.equals(headString)) {
- headData.setColumnIndex(stringKey);
- tmpHeadMap.put(stringKey, headData);
- tmpContentPropertyMap.put(stringKey, contentPropertyMapData.get(entry.getKey()));
- break;
- }
- }
- }
- excelHeadPropertyData.setHeadMap(tmpHeadMap);
- excelHeadPropertyData.setContentPropertyMap(tmpContentPropertyMap);
- }
-
public List getReadListenerList() {
return readListenerList;
}
diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java
index 9916015..d81df87 100644
--- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java
+++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java
@@ -1,6 +1,10 @@
package com.alibaba.excel.read.metadata.holder;
+import java.util.Map;
+
import com.alibaba.excel.enums.HolderEnum;
+import com.alibaba.excel.enums.RowTypeEnum;
+import com.alibaba.excel.metadata.Cell;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.Holder;
@@ -14,7 +18,14 @@ public class ReadRowHolder implements Holder {
* Returns row index of a row in the sheet that contains this cell.Start form 0.
*/
private Integer rowIndex;
-
+ /**
+ * Row type
+ */
+ private RowTypeEnum rowType;
+ /**
+ * Cell map
+ */
+ private Map cellMap;
/**
* The result of the previous listener
*/
@@ -24,9 +35,12 @@ public class ReadRowHolder implements Holder {
*/
private GlobalConfiguration globalConfiguration;
- public ReadRowHolder(Integer rowIndex, GlobalConfiguration globalConfiguration) {
+ public ReadRowHolder(Integer rowIndex, RowTypeEnum rowType, GlobalConfiguration globalConfiguration,
+ Map cellMap) {
this.rowIndex = rowIndex;
+ this.rowType = rowType;
this.globalConfiguration = globalConfiguration;
+ this.cellMap = cellMap;
}
public GlobalConfiguration getGlobalConfiguration() {
@@ -53,6 +67,22 @@ public class ReadRowHolder implements Holder {
this.rowIndex = rowIndex;
}
+ public RowTypeEnum getRowType() {
+ return rowType;
+ }
+
+ public void setRowType(RowTypeEnum rowType) {
+ this.rowType = rowType;
+ }
+
+ public Map getCellMap() {
+ return cellMap;
+ }
+
+ public void setCellMap(Map cellMap) {
+ this.cellMap = cellMap;
+ }
+
@Override
public HolderEnum holderType() {
return HolderEnum.ROW;
diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java
index 84dd4c4..87185dc 100644
--- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java
+++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java
@@ -1,6 +1,12 @@
package com.alibaba.excel.read.metadata.holder;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
import com.alibaba.excel.enums.HolderEnum;
+import com.alibaba.excel.metadata.Cell;
+import com.alibaba.excel.metadata.CellData;
+import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.metadata.ReadSheet;
/**
@@ -29,6 +35,22 @@ public class ReadSheetHolder extends AbstractReadHolder {
* Gets the total number of rows , data may be inaccurate
*/
private Integer approximateTotalRowNumber;
+ /**
+ * Data storage of the current row.
+ */
+ private Map cellMap;
+ /**
+ * Data storage of the current extra cell.
+ */
+ private CellExtra cellExtra;
+ /**
+ * Index of the current row.
+ */
+ private Integer rowIndex;
+ /**
+ * Current CellData
+ */
+ private CellData tempCellData;
public ReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) {
super(readSheet, readWorkbookHolder, readWorkbookHolder.getReadWorkbook().getConvertAllFiled());
@@ -36,6 +58,7 @@ public class ReadSheetHolder extends AbstractReadHolder {
this.parentReadWorkbookHolder = readWorkbookHolder;
this.sheetNo = readSheet.getSheetNo();
this.sheetName = readSheet.getSheetName();
+ this.cellMap = new LinkedHashMap();
}
public ReadSheet getReadSheet() {
@@ -71,7 +94,6 @@ public class ReadSheetHolder extends AbstractReadHolder {
}
/**
- *
* Approximate total number of rows
*
* @return
@@ -95,6 +117,38 @@ public class ReadSheetHolder extends AbstractReadHolder {
this.approximateTotalRowNumber = approximateTotalRowNumber;
}
+ public Map getCellMap() {
+ return cellMap;
+ }
+
+ public void setCellMap(Map cellMap) {
+ this.cellMap = cellMap;
+ }
+
+ public Integer getRowIndex() {
+ return rowIndex;
+ }
+
+ public void setRowIndex(Integer rowIndex) {
+ this.rowIndex = rowIndex;
+ }
+
+ public CellData getTempCellData() {
+ return tempCellData;
+ }
+
+ public void setTempCellData(CellData tempCellData) {
+ this.tempCellData = tempCellData;
+ }
+
+ public CellExtra getCellExtra() {
+ return cellExtra;
+ }
+
+ public void setCellExtra(CellExtra cellExtra) {
+ this.cellExtra = cellExtra;
+ }
+
@Override
public HolderEnum holderType() {
return HolderEnum.SHEET;
diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java
index cbda93f..375e32c 100644
--- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java
+++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java
@@ -1,24 +1,21 @@
package com.alibaba.excel.read.metadata.holder;
-import java.io.BufferedInputStream;
import java.io.File;
import java.io.InputStream;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
-import javax.xml.parsers.SAXParserFactory;
-
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-
import com.alibaba.excel.cache.ReadCache;
import com.alibaba.excel.cache.selector.EternalReadCacheSelector;
import com.alibaba.excel.cache.selector.ReadCacheSelector;
import com.alibaba.excel.cache.selector.SimpleReadCacheSelector;
import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.enums.HolderEnum;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException;
+import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.read.metadata.ReadWorkbook;
import com.alibaba.excel.support.ExcelTypeEnum;
@@ -86,16 +83,24 @@ public class ReadWorkbookHolder extends AbstractReadHolder {
*/
private String password;
/**
- * SAXParserFactory used when reading xlsx.
- *
- * The default will automatically find.
- *
- * Please pass in the name of a class ,like : "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"
+ * Read some additional fields. None are read by default.
*
- * @see SAXParserFactory#newInstance()
- * @see SAXParserFactory#newInstance(String, ClassLoader)
+ * @see CellExtraTypeEnum
*/
- private String xlsxSAXParserFactoryName;
+ private Set extraReadSet;
+ /**
+ * Actual sheet data
+ */
+ private List actualSheetDataList;
+ /**
+ * Parameter sheet data
+ */
+ private List parameterSheetDataList;
+ /**
+ * Read all
+ */
+ private Boolean readAll;
+
/**
* The default is all excel objects.if true , you can use {@link com.alibaba.excel.annotation.ExcelIgnore} ignore a
* field. if false , you must use {@link com.alibaba.excel.annotation.ExcelProperty} to use a filed.
@@ -115,35 +120,14 @@ public class ReadWorkbookHolder extends AbstractReadHolder {
* Prevent repeating sheet
*/
private Set hasReadSheet;
- /**
- * Package
- */
- private OPCPackage opcPackage;
- /**
- * File System
- */
- private POIFSFileSystem poifsFileSystem;
-
- /**
- * Excel 2003 cannot read specific sheet. It can only read sheet by sheet.So when you specify one sheet, you ignore
- * the others.
- */
- private Boolean ignoreRecord03;
public ReadWorkbookHolder(ReadWorkbook readWorkbook) {
super(readWorkbook, null, readWorkbook.getConvertAllFiled());
this.readWorkbook = readWorkbook;
if (readWorkbook.getInputStream() != null) {
- if (readWorkbook.getInputStream().markSupported()) {
- this.inputStream = readWorkbook.getInputStream();
- } else {
- this.inputStream = new BufferedInputStream(readWorkbook.getInputStream());
- }
+ this.inputStream = readWorkbook.getInputStream();
}
this.file = readWorkbook.getFile();
- if (file == null && inputStream == null) {
- throw new ExcelAnalysisException("File and inputStream must be a non-null.");
- }
if (readWorkbook.getMandatoryUseInputStream() == null) {
this.mandatoryUseInputStream = Boolean.FALSE;
} else {
@@ -155,13 +139,6 @@ public class ReadWorkbookHolder extends AbstractReadHolder {
this.autoCloseStream = readWorkbook.getAutoCloseStream();
}
- // The type of excel is read according to the judgment.Because encrypted XLSX needs to be specified as XLS to
- // properly parse.
- this.excelType = ExcelTypeEnum.valueOf(file, inputStream, readWorkbook.getExcelType());
-
- if (ExcelTypeEnum.XLS == excelType && getGlobalConfiguration().getUse1904windowing() == null) {
- getGlobalConfiguration().setUse1904windowing(Boolean.FALSE);
- }
this.customObject = readWorkbook.getCustomObject();
if (readWorkbook.getIgnoreEmptyRow() == null) {
this.ignoreEmptyRow = Boolean.TRUE;
@@ -185,9 +162,12 @@ public class ReadWorkbookHolder extends AbstractReadHolder {
} else {
this.defaultReturnMap = readWorkbook.getDefaultReturnMap();
}
- this.xlsxSAXParserFactoryName = readWorkbook.getXlsxSAXParserFactoryName();
+ if (readWorkbook.getExtraReadSet() == null) {
+ this.extraReadSet = new HashSet();
+ } else {
+ this.extraReadSet = readWorkbook.getExtraReadSet();
+ }
this.hasReadSheet = new HashSet();
- this.ignoreRecord03 = Boolean.FALSE;
this.password = readWorkbook.getPassword();
}
@@ -303,44 +283,44 @@ public class ReadWorkbookHolder extends AbstractReadHolder {
this.defaultReturnMap = defaultReturnMap;
}
- public OPCPackage getOpcPackage() {
- return opcPackage;
+ public String getPassword() {
+ return password;
}
- public void setOpcPackage(OPCPackage opcPackage) {
- this.opcPackage = opcPackage;
+ public void setPassword(String password) {
+ this.password = password;
}
- public POIFSFileSystem getPoifsFileSystem() {
- return poifsFileSystem;
+ public Set getExtraReadSet() {
+ return extraReadSet;
}
- public void setPoifsFileSystem(POIFSFileSystem poifsFileSystem) {
- this.poifsFileSystem = poifsFileSystem;
+ public void setExtraReadSet(Set extraReadSet) {
+ this.extraReadSet = extraReadSet;
}
- public Boolean getIgnoreRecord03() {
- return ignoreRecord03;
+ public List getActualSheetDataList() {
+ return actualSheetDataList;
}
- public void setIgnoreRecord03(Boolean ignoreRecord03) {
- this.ignoreRecord03 = ignoreRecord03;
+ public void setActualSheetDataList(List actualSheetDataList) {
+ this.actualSheetDataList = actualSheetDataList;
}
- public String getPassword() {
- return password;
+ public List getParameterSheetDataList() {
+ return parameterSheetDataList;
}
- public void setPassword(String password) {
- this.password = password;
+ public void setParameterSheetDataList(List parameterSheetDataList) {
+ this.parameterSheetDataList = parameterSheetDataList;
}
- public String getXlsxSAXParserFactoryName() {
- return xlsxSAXParserFactoryName;
+ public Boolean getReadAll() {
+ return readAll;
}
- public void setXlsxSAXParserFactoryName(String xlsxSAXParserFactoryName) {
- this.xlsxSAXParserFactoryName = xlsxSAXParserFactoryName;
+ public void setReadAll(Boolean readAll) {
+ this.readAll = readAll;
}
@Override
diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java
new file mode 100644
index 0000000..d0171ff
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java
@@ -0,0 +1,72 @@
+package com.alibaba.excel.read.metadata.holder.xls;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.alibaba.excel.enums.RowTypeEnum;
+import com.alibaba.excel.read.metadata.ReadSheet;
+import com.alibaba.excel.read.metadata.holder.ReadSheetHolder;
+import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
+
+/**
+ * sheet holder
+ *
+ * @author Jiaju Zhuang
+ */
+public class XlsReadSheetHolder extends ReadSheetHolder {
+ /**
+ * Row type.Temporary storage, last set in ReadRowHolder
.
+ */
+ private RowTypeEnum tempRowType;
+ /**
+ * Ignore record.
+ */
+ private Boolean ignoreRecord;
+ /**
+ * Temp object index.
+ */
+ private Integer tempObjectIndex;
+ /**
+ * Temp object index.
+ */
+ private Map objectCacheMap;
+
+ public XlsReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) {
+ super(readSheet, readWorkbookHolder);
+ ignoreRecord = Boolean.FALSE;
+ tempRowType = RowTypeEnum.EMPTY;
+ objectCacheMap = new HashMap(16);
+ }
+
+ public RowTypeEnum getTempRowType() {
+ return tempRowType;
+ }
+
+ public void setTempRowType(RowTypeEnum tempRowType) {
+ this.tempRowType = tempRowType;
+ }
+
+ public Boolean getIgnoreRecord() {
+ return ignoreRecord;
+ }
+
+ public void setIgnoreRecord(Boolean ignoreRecord) {
+ this.ignoreRecord = ignoreRecord;
+ }
+
+ public Integer getTempObjectIndex() {
+ return tempObjectIndex;
+ }
+
+ public void setTempObjectIndex(Integer tempObjectIndex) {
+ this.tempObjectIndex = tempObjectIndex;
+ }
+
+ public Map getObjectCacheMap() {
+ return objectCacheMap;
+ }
+
+ public void setObjectCacheMap(Map objectCacheMap) {
+ this.objectCacheMap = objectCacheMap;
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java
new file mode 100644
index 0000000..70c1c03
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java
@@ -0,0 +1,103 @@
+package com.alibaba.excel.read.metadata.holder.xls;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
+import org.apache.poi.hssf.record.BoundSheetRecord;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+import com.alibaba.excel.read.metadata.ReadWorkbook;
+import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
+import com.alibaba.excel.support.ExcelTypeEnum;
+
+/**
+ * Workbook holder
+ *
+ * @author Jiaju Zhuang
+ */
+public class XlsReadWorkbookHolder extends ReadWorkbookHolder {
+ /**
+ * File System
+ */
+ private POIFSFileSystem poifsFileSystem;
+ /**
+ * Format tracking HSSFListener
+ */
+ private FormatTrackingHSSFListener formatTrackingHSSFListener;
+ /**
+ * HSSFWorkbook
+ */
+ private HSSFWorkbook hssfWorkbook;
+ /**
+ * Bound sheet record list.
+ */
+ private List boundSheetRecordList;
+ /**
+ * Need read sheet.
+ */
+ private Boolean needReadSheet;
+ /**
+ * Sheet Index
+ */
+ private Integer readSheetIndex;
+
+ public XlsReadWorkbookHolder(ReadWorkbook readWorkbook) {
+ super(readWorkbook);
+ this.boundSheetRecordList = new ArrayList();
+ this.needReadSheet = Boolean.TRUE;
+ setExcelType(ExcelTypeEnum.XLS);
+ if (getGlobalConfiguration().getUse1904windowing() == null) {
+ getGlobalConfiguration().setUse1904windowing(Boolean.FALSE);
+ }
+ }
+
+ public POIFSFileSystem getPoifsFileSystem() {
+ return poifsFileSystem;
+ }
+
+ public void setPoifsFileSystem(POIFSFileSystem poifsFileSystem) {
+ this.poifsFileSystem = poifsFileSystem;
+ }
+
+ public FormatTrackingHSSFListener getFormatTrackingHSSFListener() {
+ return formatTrackingHSSFListener;
+ }
+
+ public void setFormatTrackingHSSFListener(FormatTrackingHSSFListener formatTrackingHSSFListener) {
+ this.formatTrackingHSSFListener = formatTrackingHSSFListener;
+ }
+
+ public HSSFWorkbook getHssfWorkbook() {
+ return hssfWorkbook;
+ }
+
+ public void setHssfWorkbook(HSSFWorkbook hssfWorkbook) {
+ this.hssfWorkbook = hssfWorkbook;
+ }
+
+ public List getBoundSheetRecordList() {
+ return boundSheetRecordList;
+ }
+
+ public void setBoundSheetRecordList(List boundSheetRecordList) {
+ this.boundSheetRecordList = boundSheetRecordList;
+ }
+
+ public Boolean getNeedReadSheet() {
+ return needReadSheet;
+ }
+
+ public void setNeedReadSheet(Boolean needReadSheet) {
+ this.needReadSheet = needReadSheet;
+ }
+
+ public Integer getReadSheetIndex() {
+ return readSheetIndex;
+ }
+
+ public void setReadSheetIndex(Integer readSheetIndex) {
+ this.readSheetIndex = readSheetIndex;
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java
new file mode 100644
index 0000000..46b9281
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java
@@ -0,0 +1,69 @@
+package com.alibaba.excel.read.metadata.holder.xlsx;
+
+import java.util.Deque;
+import java.util.LinkedList;
+
+import com.alibaba.excel.read.metadata.ReadSheet;
+import com.alibaba.excel.read.metadata.holder.ReadSheetHolder;
+import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
+
+/**
+ * sheet holder
+ *
+ * @author Jiaju Zhuang
+ */
+public class XlsxReadSheetHolder extends ReadSheetHolder {
+ /**
+ * Record the label of the current operation to prevent NPE.
+ */
+ private Deque tagDeque;
+ /**
+ * Current Column
+ */
+ private Integer columnIndex;
+ /**
+ * Data for current label.
+ */
+ private StringBuilder tempData;
+ /**
+ * Formula for current label.
+ */
+ private StringBuilder tempFormula;
+
+ public XlsxReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) {
+ super(readSheet, readWorkbookHolder);
+ this.tagDeque = new LinkedList();
+ }
+
+ public Deque getTagDeque() {
+ return tagDeque;
+ }
+
+ public void setTagDeque(Deque tagDeque) {
+ this.tagDeque = tagDeque;
+ }
+
+ public Integer getColumnIndex() {
+ return columnIndex;
+ }
+
+ public void setColumnIndex(Integer columnIndex) {
+ this.columnIndex = columnIndex;
+ }
+
+ public StringBuilder getTempData() {
+ return tempData;
+ }
+
+ public void setTempData(StringBuilder tempData) {
+ this.tempData = tempData;
+ }
+
+ public StringBuilder getTempFormula() {
+ return tempFormula;
+ }
+
+ public void setTempFormula(StringBuilder tempFormula) {
+ this.tempFormula = tempFormula;
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java
new file mode 100644
index 0000000..066131d
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java
@@ -0,0 +1,67 @@
+package com.alibaba.excel.read.metadata.holder.xlsx;
+
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.xssf.model.StylesTable;
+
+import com.alibaba.excel.read.metadata.ReadWorkbook;
+import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
+import com.alibaba.excel.support.ExcelTypeEnum;
+
+/**
+ * Workbook holder
+ *
+ * @author Jiaju Zhuang
+ */
+public class XlsxReadWorkbookHolder extends ReadWorkbookHolder {
+ /**
+ * Package
+ */
+ private OPCPackage opcPackage;
+ /**
+ * SAXParserFactory used when reading xlsx.
+ *
+ * The default will automatically find.
+ *
+ * Please pass in the name of a class ,like : "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"
+ *
+ * @see SAXParserFactory#newInstance()
+ * @see SAXParserFactory#newInstance(String, ClassLoader)
+ */
+ private String saxParserFactoryName;
+ /**
+ * Current style information
+ */
+ private StylesTable stylesTable;
+
+ public XlsxReadWorkbookHolder(ReadWorkbook readWorkbook) {
+ super(readWorkbook);
+ this.saxParserFactoryName = readWorkbook.getXlsxSAXParserFactoryName();
+ setExcelType(ExcelTypeEnum.XLSX);
+ }
+
+ public OPCPackage getOpcPackage() {
+ return opcPackage;
+ }
+
+ public void setOpcPackage(OPCPackage opcPackage) {
+ this.opcPackage = opcPackage;
+ }
+
+ public String getSaxParserFactoryName() {
+ return saxParserFactoryName;
+ }
+
+ public void setSaxParserFactoryName(String saxParserFactoryName) {
+ this.saxParserFactoryName = saxParserFactoryName;
+ }
+
+ public StylesTable getStylesTable() {
+ return stylesTable;
+ }
+
+ public void setStylesTable(StylesTable stylesTable) {
+ this.stylesTable = stylesTable;
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/read/processor/AnalysisEventProcessor.java b/src/main/java/com/alibaba/excel/read/processor/AnalysisEventProcessor.java
new file mode 100644
index 0000000..360ae97
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/read/processor/AnalysisEventProcessor.java
@@ -0,0 +1,33 @@
+package com.alibaba.excel.read.processor;
+
+import com.alibaba.excel.context.AnalysisContext;
+
+/**
+ *
+ * Event processor
+ *
+ * @author jipengfei
+ */
+public interface AnalysisEventProcessor {
+ /**
+ * Read extra information
+ *
+ * @param analysisContext
+ */
+ void extra(AnalysisContext analysisContext);
+
+ /**
+ * End row
+ *
+ * @param analysisContext
+ */
+ void endRow(AnalysisContext analysisContext);
+
+ /**
+ * Notify after all analysed
+ *
+ * @param analysisContext
+ * Analysis context
+ */
+ void endSheet(AnalysisContext analysisContext);
+}
diff --git a/src/main/java/com/alibaba/excel/read/processor/DefaultAnalysisEventProcessor.java b/src/main/java/com/alibaba/excel/read/processor/DefaultAnalysisEventProcessor.java
new file mode 100644
index 0000000..ddd1950
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/read/processor/DefaultAnalysisEventProcessor.java
@@ -0,0 +1,157 @@
+package com.alibaba.excel.read.processor;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.enums.HeadKindEnum;
+import com.alibaba.excel.enums.RowTypeEnum;
+import com.alibaba.excel.exception.ExcelAnalysisException;
+import com.alibaba.excel.exception.ExcelAnalysisStopException;
+import com.alibaba.excel.metadata.CellData;
+import com.alibaba.excel.metadata.Head;
+import com.alibaba.excel.metadata.property.ExcelContentProperty;
+import com.alibaba.excel.read.listener.ReadListener;
+import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
+import com.alibaba.excel.read.metadata.property.ExcelReadHeadProperty;
+import com.alibaba.excel.util.ConverterUtils;
+import com.alibaba.excel.util.StringUtils;
+
+/**
+ * Analysis event
+ *
+ * @author jipengfei
+ */
+public class DefaultAnalysisEventProcessor implements AnalysisEventProcessor {
+ private static final Logger LOGGER = LoggerFactory.getLogger(DefaultAnalysisEventProcessor.class);
+
+ @Override
+ public void extra(AnalysisContext analysisContext) {
+ dealExtra(analysisContext);
+ }
+
+ @Override
+ public void endRow(AnalysisContext analysisContext) {
+ if (RowTypeEnum.EMPTY.equals(analysisContext.readRowHolder().getRowType())) {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.warn("Empty row!");
+ }
+ if (analysisContext.readWorkbookHolder().getIgnoreEmptyRow()) {
+ return;
+ }
+ }
+ dealData(analysisContext);
+ }
+
+ @Override
+ public void endSheet(AnalysisContext analysisContext) {
+ for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) {
+ readListener.doAfterAllAnalysed(analysisContext);
+ }
+ }
+
+ private void dealExtra(AnalysisContext analysisContext) {
+ for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) {
+ try {
+ readListener.extra(analysisContext.readSheetHolder().getCellExtra(), analysisContext);
+ } catch (Exception e) {
+ onException(analysisContext, e);
+ break;
+ }
+ if (!readListener.hasNext(analysisContext)) {
+ throw new ExcelAnalysisStopException();
+ }
+ }
+ }
+
+ private void onException(AnalysisContext analysisContext, Exception e) {
+ for (ReadListener readListenerException : analysisContext.currentReadHolder().readListenerList()) {
+ try {
+ readListenerException.onException(e, analysisContext);
+ } catch (RuntimeException re) {
+ throw re;
+ } catch (Exception e1) {
+ throw new ExcelAnalysisException(e1.getMessage(), e1);
+ }
+ }
+ }
+
+ private void dealData(AnalysisContext analysisContext) {
+ ReadRowHolder readRowHolder = analysisContext.readRowHolder();
+ Map cellDataMap = (Map)readRowHolder.getCellMap();
+ readRowHolder.setCurrentRowAnalysisResult(cellDataMap);
+ int rowIndex = readRowHolder.getRowIndex();
+ int currentHeadRowNumber = analysisContext.readSheetHolder().getHeadRowNumber();
+
+ boolean isData = rowIndex >= currentHeadRowNumber;
+
+ // Last head column
+ if (!isData && currentHeadRowNumber == rowIndex + 1) {
+ buildHead(analysisContext, cellDataMap);
+ }
+ // Now is data
+ for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) {
+ try {
+ if (isData) {
+ readListener.invoke(readRowHolder.getCurrentRowAnalysisResult(), analysisContext);
+ } else {
+ readListener.invokeHead(cellDataMap, analysisContext);
+ }
+ } catch (Exception e) {
+ onException(analysisContext, e);
+ break;
+ }
+ if (!readListener.hasNext(analysisContext)) {
+ throw new ExcelAnalysisStopException();
+ }
+ }
+ }
+
+ private void buildHead(AnalysisContext analysisContext, Map cellDataMap) {
+ if (!HeadKindEnum.CLASS.equals(analysisContext.currentReadHolder().excelReadHeadProperty().getHeadKind())) {
+ return;
+ }
+ Map dataMap = ConverterUtils.convertToStringMap(cellDataMap, analysisContext);
+ ExcelReadHeadProperty excelHeadPropertyData = analysisContext.readSheetHolder().excelReadHeadProperty();
+ Map headMapData = excelHeadPropertyData.getHeadMap();
+ Map contentPropertyMapData = excelHeadPropertyData.getContentPropertyMap();
+ Map tmpHeadMap = new HashMap(headMapData.size() * 4 / 3 + 1);
+ Map tmpContentPropertyMap =
+ new HashMap(contentPropertyMapData.size() * 4 / 3 + 1);
+ for (Map.Entry entry : headMapData.entrySet()) {
+ Head headData = entry.getValue();
+ if (headData.getForceIndex() || !headData.getForceName()) {
+ tmpHeadMap.put(entry.getKey(), headData);
+ tmpContentPropertyMap.put(entry.getKey(), contentPropertyMapData.get(entry.getKey()));
+ continue;
+ }
+ List headNameList = headData.getHeadNameList();
+ String headName = headNameList.get(headNameList.size() - 1);
+ for (Map.Entry stringEntry : dataMap.entrySet()) {
+ if (stringEntry == null) {
+ continue;
+ }
+ String headString = stringEntry.getValue();
+ Integer stringKey = stringEntry.getKey();
+ if (StringUtils.isEmpty(headString)) {
+ continue;
+ }
+ if (analysisContext.currentReadHolder().globalConfiguration().getAutoTrim()) {
+ headString = headString.trim();
+ }
+ if (headName.equals(headString)) {
+ headData.setColumnIndex(stringKey);
+ tmpHeadMap.put(stringKey, headData);
+ tmpContentPropertyMap.put(stringKey, contentPropertyMapData.get(entry.getKey()));
+ break;
+ }
+ }
+ }
+ excelHeadPropertyData.setHeadMap(tmpHeadMap);
+ excelHeadPropertyData.setContentPropertyMap(tmpContentPropertyMap);
+ }
+}
diff --git a/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java b/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java
index b4e41df..cdca07f 100644
--- a/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java
+++ b/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java
@@ -3,12 +3,14 @@ package com.alibaba.excel.support;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
-import java.io.IOException;
import java.io.InputStream;
import org.apache.poi.poifs.filesystem.FileMagic;
+import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelCommonException;
+import com.alibaba.excel.read.metadata.ReadWorkbook;
+import com.alibaba.excel.util.StringUtils;
/**
* @author jipengfei
@@ -29,44 +31,68 @@ public enum ExcelTypeEnum {
this.setValue(value);
}
- public static ExcelTypeEnum valueOf(File file, InputStream inputStream, ExcelTypeEnum excelType) {
+ public static ExcelTypeEnum valueOf(ReadWorkbook readWorkbook) {
+ ExcelTypeEnum excelType = readWorkbook.getExcelType();
+ if (excelType != null) {
+ return excelType;
+ }
+ File file = readWorkbook.getFile();
+ InputStream inputStream = readWorkbook.getInputStream();
+ if (file == null && inputStream == null) {
+ throw new ExcelAnalysisException("File and inputStream must be a non-null.");
+ }
try {
- FileMagic fileMagic;
if (file != null) {
- BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
- try {
- fileMagic = FileMagic.valueOf(bufferedInputStream);
- } finally {
- bufferedInputStream.close();
+ if (!file.exists()) {
+ throw new ExcelAnalysisException("File " + file.getAbsolutePath() + " not exists.");
}
- if (!FileMagic.OLE2.equals(fileMagic) && !FileMagic.OOXML.equals(fileMagic)) {
- String fileName = file.getName();
- if (fileName.endsWith(XLSX.getValue())) {
- return XLSX;
- } else if (fileName.endsWith(XLS.getValue())) {
- return XLS;
- } else {
- throw new ExcelCommonException("Unknown excel type.");
+ // If there is a password, use the FileMagic first
+ if (!StringUtils.isEmpty(readWorkbook.getPassword())) {
+ BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
+ try {
+ return recognitionExcelType(bufferedInputStream);
+ } finally {
+ bufferedInputStream.close();
+ }
+ }
+ // Use the name to determine the type
+ String fileName = file.getName();
+ if (fileName.endsWith(XLSX.getValue())) {
+ return XLSX;
+ } else if (fileName.endsWith(XLS.getValue())) {
+ return XLS;
+ }
+ if (StringUtils.isEmpty(readWorkbook.getPassword())) {
+ BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
+ try {
+ return recognitionExcelType(bufferedInputStream);
+ } finally {
+ bufferedInputStream.close();
}
}
- } else {
- fileMagic = FileMagic.valueOf(inputStream);
- }
- if (FileMagic.OLE2.equals(fileMagic)) {
- return XLS;
- }
- if (FileMagic.OOXML.equals(fileMagic)) {
- return XLSX;
}
- } catch (IOException e) {
- if (excelType != null) {
- return excelType;
+ if (!inputStream.markSupported()) {
+ inputStream = new BufferedInputStream(inputStream);
+ readWorkbook.setInputStream(inputStream);
}
+ return recognitionExcelType(inputStream);
+ } catch (ExcelCommonException e) {
+ throw e;
+ } catch (ExcelAnalysisException e) {
+ throw e;
+ } catch (Exception e) {
throw new ExcelCommonException(
"Convert excel format exception.You can try specifying the 'excelType' yourself", e);
}
- if (excelType != null) {
- return excelType;
+ }
+
+ private static ExcelTypeEnum recognitionExcelType(InputStream inputStream) throws Exception {
+ FileMagic fileMagic = FileMagic.valueOf(inputStream);
+ if (FileMagic.OLE2.equals(fileMagic)) {
+ return XLS;
+ }
+ if (FileMagic.OOXML.equals(fileMagic)) {
+ return XLSX;
}
throw new ExcelCommonException(
"Convert excel format exception.You can try specifying the 'excelType' yourself");
diff --git a/src/main/java/com/alibaba/excel/util/DateUtils.java b/src/main/java/com/alibaba/excel/util/DateUtils.java
index a581a95..815257b 100644
--- a/src/main/java/com/alibaba/excel/util/DateUtils.java
+++ b/src/main/java/com/alibaba/excel/util/DateUtils.java
@@ -1,10 +1,12 @@
package com.alibaba.excel.util;
+import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
-
-import com.alibaba.excel.exception.ExcelDataConvertException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
/**
* Date utils
@@ -12,6 +14,33 @@ import com.alibaba.excel.exception.ExcelDataConvertException;
* @author Jiaju Zhuang
**/
public class DateUtils {
+ /**
+ * Is a cache of dates
+ */
+ private static final ThreadLocal