Browse Source

Merge branch '2.1.x' into feature/longest_match_cache_remove_static_bug

pull/872/head
Jiaju Zhuang 5 years ago committed by GitHub
parent
commit
4b8564c9e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .travis.yml
  2. 6
      README.md
  3. 17
      pom.xml
  4. 77
      src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
  5. 7
      src/main/java/com/alibaba/excel/analysis/ExcelReadExecutor.java
  6. 33
      src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java
  7. 8
      src/main/java/com/alibaba/excel/analysis/v03/IgnorableXlsRecordHandler.java
  8. 44
      src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java
  9. 48
      src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java
  10. 241
      src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java
  11. 19
      src/main/java/com/alibaba/excel/analysis/v03/handlers/AbstractXlsRecordHandler.java
  12. 47
      src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java
  13. 23
      src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankRecordHandler.java
  14. 121
      src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java
  15. 25
      src/main/java/com/alibaba/excel/analysis/v03/handlers/BoolErrRecordHandler.java
  16. 21
      src/main/java/com/alibaba/excel/analysis/v03/handlers/BoundSheetRecordHandler.java
  17. 41
      src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordHandler.java
  18. 21
      src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java
  19. 106
      src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java
  20. 30
      src/main/java/com/alibaba/excel/analysis/v03/handlers/HyperlinkRecordHandler.java
  21. 32
      src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java
  22. 31
      src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java
  23. 42
      src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSstRecordHandler.java
  24. 35
      src/main/java/com/alibaba/excel/analysis/v03/handlers/MergeCellsRecordHandler.java
  25. 38
      src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java
  26. 33
      src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java
  27. 45
      src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java
  28. 30
      src/main/java/com/alibaba/excel/analysis/v03/handlers/ObjRecordHandler.java
  29. 30
      src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java
  30. 41
      src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java
  31. 35
      src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java
  32. 38
      src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java
  33. 37
      src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java
  34. 27
      src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java
  35. 55
      src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java
  36. 33
      src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java
  37. 113
      src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java
  38. 66
      src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java
  39. 32
      src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractXlsxTagHandler.java
  40. 32
      src/main/java/com/alibaba/excel/analysis/v07/handlers/CellFormulaTagHandler.java
  41. 23
      src/main/java/com/alibaba/excel/analysis/v07/handlers/CellInlineStringValueTagHandler.java
  42. 57
      src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java
  43. 34
      src/main/java/com/alibaba/excel/analysis/v07/handlers/CellValueTagHandler.java
  44. 42
      src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java
  45. 23
      src/main/java/com/alibaba/excel/analysis/v07/handlers/CountTagHandler.java
  46. 184
      src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java
  47. 35
      src/main/java/com/alibaba/excel/analysis/v07/handlers/HyperlinkTagHandler.java
  48. 34
      src/main/java/com/alibaba/excel/analysis/v07/handlers/MergeCellTagHandler.java
  49. 48
      src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java
  50. 51
      src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java
  51. 54
      src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxTagHandler.java
  52. 2
      src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/SharedStringsTableHandler.java
  53. 93
      src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/XlsxRowHandler.java
  54. 89
      src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java
  55. 31
      src/main/java/com/alibaba/excel/annotation/write/style/ContentLoopMerge.java
  56. 159
      src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java
  57. 89
      src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java
  58. 159
      src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java
  59. 45
      src/main/java/com/alibaba/excel/annotation/write/style/OnceAbsoluteMerge.java
  60. 37
      src/main/java/com/alibaba/excel/cache/XlsCache.java
  61. 379
      src/main/java/com/alibaba/excel/constant/BuiltinFormats.java
  62. 52
      src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java
  63. 24
      src/main/java/com/alibaba/excel/context/AnalysisContext.java
  64. 51
      src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java
  65. 79
      src/main/java/com/alibaba/excel/context/WriteContextImpl.java
  66. 30
      src/main/java/com/alibaba/excel/context/xls/DefaultXlsReadContext.java
  67. 26
      src/main/java/com/alibaba/excel/context/xls/XlsReadContext.java
  68. 30
      src/main/java/com/alibaba/excel/context/xlsx/DefaultXlsxReadContext.java
  69. 26
      src/main/java/com/alibaba/excel/context/xlsx/XlsxReadContext.java
  70. 101
      src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java
  71. 2
      src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java
  72. 2
      src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java
  73. 2
      src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java
  74. 2
      src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java
  75. 12
      src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java
  76. 21
      src/main/java/com/alibaba/excel/enums/CellExtraTypeEnum.java
  77. 17
      src/main/java/com/alibaba/excel/enums/RowTypeEnum.java
  78. 12
      src/main/java/com/alibaba/excel/event/AbstractIgnoreExceptionReadListener.java
  79. 12
      src/main/java/com/alibaba/excel/event/AnalysisEventListener.java
  80. 33
      src/main/java/com/alibaba/excel/metadata/AbstractCell.java
  81. 12
      src/main/java/com/alibaba/excel/metadata/AbstractHolder.java
  82. 98
      src/main/java/com/alibaba/excel/metadata/AbstractParameterBuilder.java
  83. 13
      src/main/java/com/alibaba/excel/metadata/BasicParameter.java
  84. 22
      src/main/java/com/alibaba/excel/metadata/Cell.java
  85. 38
      src/main/java/com/alibaba/excel/metadata/CellData.java
  86. 121
      src/main/java/com/alibaba/excel/metadata/CellExtra.java
  87. 786
      src/main/java/com/alibaba/excel/metadata/DataFormatter.java
  88. 15
      src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java
  89. 63
      src/main/java/com/alibaba/excel/metadata/Head.java
  90. 12
      src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java
  91. 180
      src/main/java/com/alibaba/excel/metadata/property/FontProperty.java
  92. 47
      src/main/java/com/alibaba/excel/metadata/property/LoopMergeProperty.java
  93. 74
      src/main/java/com/alibaba/excel/metadata/property/OnceAbsoluteMergeProperty.java
  94. 377
      src/main/java/com/alibaba/excel/metadata/property/StyleProperty.java
  95. 47
      src/main/java/com/alibaba/excel/read/builder/AbstractExcelReaderParameterBuilder.java
  96. 141
      src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java
  97. 101
      src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java
  98. 10
      src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java
  99. 11
      src/main/java/com/alibaba/excel/read/listener/ReadListener.java
  100. 39
      src/main/java/com/alibaba/excel/read/listener/ReadListenerRegistryCenter.java
  101. Some files were not shown because too many files have changed in this diff Show More

2
.travis.yml

@ -6,5 +6,5 @@ cache:
before_install: before_install:
- chmod +x mvnw - chmod +x mvnw
install: install:
- ./mvnw install -Dgpg.skip -B -V -Dmaven.test.skip=true - ./mvnw install -B -V -Dmaven.test.skip=true
- ./mvnw javadoc:javadoc - ./mvnw javadoc:javadoc

6
README.md

@ -7,6 +7,7 @@ easyexcel
[QQ群: 662022184](//shang.qq.com/wpa/qunwpa?idkey=53d9d821b0833e3c14670f007488a61e300f00ff4f1b81fd950590d90dd80f80) [QQ群: 662022184](//shang.qq.com/wpa/qunwpa?idkey=53d9d821b0833e3c14670f007488a61e300f00ff4f1b81fd950590d90dd80f80)
[钉钉群: 21960511](https://qr.dingtalk.com/action/joingroup?code=v1,k1,cchz6k12ci9B08NNqhNRFGXocNVHrZtW0kaOtTKg/Rk=&_dt_no_comment=1&origin=11) [钉钉群: 21960511](https://qr.dingtalk.com/action/joingroup?code=v1,k1,cchz6k12ci9B08NNqhNRFGXocNVHrZtW0kaOtTKg/Rk=&_dt_no_comment=1&origin=11)
[官方网站: https://alibaba-easyexcel.github.io/](https://alibaba-easyexcel.github.io/) [官方网站: https://alibaba-easyexcel.github.io/](https://alibaba-easyexcel.github.io/)
#### 因为公司不方便用QQ,所以建议加钉钉群
# JAVA解析Excel工具easyexcel # JAVA解析Excel工具easyexcel
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便 Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便
@ -19,6 +20,7 @@ Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都
* [快速使用](https://alibaba-easyexcel.github.io/) * [快速使用](https://alibaba-easyexcel.github.io/)
* [关于软件](/abouteasyexcel.md) * [关于软件](/abouteasyexcel.md)
* [更新记事](/update.md) * [更新记事](/update.md)
* [贡献代码](https://alibaba-easyexcel.github.io/support/contribute.html)
## 维护者 ## 维护者
玉霄、庄家钜、怀宇 玉霄、庄家钜、怀宇
@ -30,7 +32,7 @@ DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/ja
/** /**
* 最简单的读 * 最简单的读
* <p>1. 创建excel对应的实体对象 参照{@link DemoData} * <p>1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} * <p>2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
* <p>3. 直接读即可 * <p>3. 直接读即可
*/ */
@Test @Test
@ -81,7 +83,7 @@ DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/ja
/** /**
* 文件上传 * 文件上传
* <p>1. 创建excel对应的实体对象 参照{@link UploadData} * <p>1. 创建excel对应的实体对象 参照{@link UploadData}
* <p>2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener} * <p>2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener}
* <p>3. 直接读即可 * <p>3. 直接读即可
*/ */
@PostMapping("upload") @PostMapping("upload")

17
pom.xml

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId> <artifactId>easyexcel</artifactId>
<version>2.1.3</version> <version>2.2.0-beta2</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>easyexcel</name> <name>easyexcel</name>
@ -15,9 +15,10 @@
<properties> <properties>
<!--<gpg.skip>true</gpg.skip>-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jdk.version>1.7</jdk.version> <jdk.version>1.6</jdk.version>
<gpg.skip>true</gpg.skip>
<maven.javadoc.skip>true</maven.javadoc.skip>
</properties> </properties>
<scm> <scm>
@ -66,6 +67,11 @@
<artifactId>poi-ooxml</artifactId> <artifactId>poi-ooxml</artifactId>
<version>3.17</version> <version>3.17</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.17</version>
</dependency>
<dependency> <dependency>
<groupId>cglib</groupId> <groupId>cglib</groupId>
<artifactId>cglib</artifactId> <artifactId>cglib</artifactId>
@ -79,7 +85,7 @@
<dependency> <dependency>
<groupId>org.ehcache</groupId> <groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId> <artifactId>ehcache</artifactId>
<version>3.7.1</version> <version>3.4.0</version>
</dependency> </dependency>
<!--test--> <!--test-->
<dependency> <dependency>
@ -154,6 +160,8 @@
</rulesets> </rulesets>
<excludes> <excludes>
<exclude>com/alibaba/excel/event/AnalysisEventListener.java</exclude> <exclude>com/alibaba/excel/event/AnalysisEventListener.java</exclude>
<exclude>com/alibaba/excel/metadata/DataFormatter.java</exclude>
<exclude>com/alibaba/excel/util/DateUtils.java</exclude>
</excludes> </excludes>
</configuration> </configuration>
<executions> <executions>
@ -196,7 +204,6 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId> <artifactId>maven-gpg-plugin</artifactId>

77
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.v03.XlsSaxAnalyser;
import com.alibaba.excel.analysis.v07.XlsxSaxAnalyser; import com.alibaba.excel.analysis.v07.XlsxSaxAnalyser;
import com.alibaba.excel.context.AnalysisContext; 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.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelAnalysisStopException; import com.alibaba.excel.exception.ExcelAnalysisStopException;
import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.read.metadata.ReadWorkbook;
import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; 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.support.ExcelTypeEnum;
import com.alibaba.excel.util.CollectionUtils; import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.util.DateUtils;
import com.alibaba.excel.util.FileUtils; import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.util.NumberDataFormatterUtils;
import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.util.StringUtils;
/** /**
@ -41,8 +48,7 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
public ExcelAnalyserImpl(ReadWorkbook readWorkbook) { public ExcelAnalyserImpl(ReadWorkbook readWorkbook) {
try { try {
analysisContext = new AnalysisContextImpl(readWorkbook); choiceExcelExecutor(readWorkbook);
choiceExcelExecutor();
} catch (RuntimeException e) { } catch (RuntimeException e) {
finish(); finish();
throw e; throw e;
@ -52,29 +58,25 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
} }
} }
private void choiceExcelExecutor() throws Exception { private void choiceExcelExecutor(ReadWorkbook readWorkbook) throws Exception {
ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder(); ExcelTypeEnum excelType = ExcelTypeEnum.valueOf(readWorkbook);
ExcelTypeEnum excelType = readWorkbookHolder.getExcelType();
if (excelType == null) {
excelReadExecutor = new XlsxSaxAnalyser(analysisContext, null);
return;
}
switch (excelType) { switch (excelType) {
case XLS: case XLS:
POIFSFileSystem poifsFileSystem; POIFSFileSystem poifsFileSystem;
if (readWorkbookHolder.getFile() != null) { if (readWorkbook.getFile() != null) {
poifsFileSystem = new POIFSFileSystem(readWorkbookHolder.getFile()); poifsFileSystem = new POIFSFileSystem(readWorkbook.getFile());
} else { } else {
poifsFileSystem = new POIFSFileSystem(readWorkbookHolder.getInputStream()); poifsFileSystem = new POIFSFileSystem(readWorkbook.getInputStream());
} }
// So in encrypted excel, it looks like XLS but it's actually XLSX // So in encrypted excel, it looks like XLS but it's actually XLSX
if (poifsFileSystem.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) { if (poifsFileSystem.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) {
InputStream decryptedStream = null; InputStream decryptedStream = null;
try { try {
decryptedStream = decryptedStream = DocumentFactoryHelper
DocumentFactoryHelper.getDecryptedStream(poifsFileSystem.getRoot().getFileSystem(), .getDecryptedStream(poifsFileSystem.getRoot().getFileSystem(), readWorkbook.getPassword());
analysisContext.readWorkbookHolder().getPassword()); XlsxReadContext xlsxReadContext = new DefaultXlsxReadContext(readWorkbook, ExcelTypeEnum.XLSX);
excelReadExecutor = new XlsxSaxAnalyser(analysisContext, decryptedStream); analysisContext = xlsxReadContext;
excelReadExecutor = new XlsxSaxAnalyser(xlsxReadContext, decryptedStream);
return; return;
} finally { } finally {
IOUtils.closeQuietly(decryptedStream); IOUtils.closeQuietly(decryptedStream);
@ -83,15 +85,21 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
poifsFileSystem.close(); poifsFileSystem.close();
} }
} }
if (analysisContext.readWorkbookHolder().getPassword() != null) { if (readWorkbook.getPassword() != null) {
Biff8EncryptionKey.setCurrentUserPassword(analysisContext.readWorkbookHolder().getPassword()); 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; break;
case XLSX: case XLSX:
excelReadExecutor = new XlsxSaxAnalyser(analysisContext, null); XlsxReadContext xlsxReadContext = new DefaultXlsxReadContext(readWorkbook, ExcelTypeEnum.XLSX);
analysisContext = xlsxReadContext;
excelReadExecutor = new XlsxSaxAnalyser(xlsxReadContext, null);
break; break;
default: default:
break;
} }
} }
@ -101,19 +109,15 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
if (!readAll && CollectionUtils.isEmpty(readSheetList)) { if (!readAll && CollectionUtils.isEmpty(readSheetList)) {
throw new IllegalArgumentException("Specify at least one read sheet."); throw new IllegalArgumentException("Specify at least one read sheet.");
} }
analysisContext.readWorkbookHolder().setParameterSheetDataList(readSheetList);
analysisContext.readWorkbookHolder().setReadAll(readAll);
try { try {
excelReadExecutor.execute(readSheetList, readAll); excelReadExecutor.execute();
} catch (ExcelAnalysisStopException e) { } catch (ExcelAnalysisStopException e) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Custom stop!"); LOGGER.debug("Custom stop!");
} }
} }
// The last sheet is read
if (excelReadExecutor instanceof XlsSaxAnalyser) {
if (analysisContext.readSheetHolder() != null) {
analysisContext.readSheetHolder().notifyAfterAllAnalysed(analysisContext);
}
}
} catch (RuntimeException e) { } catch (RuntimeException e) {
finish(); finish();
throw e; throw e;
@ -144,15 +148,17 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
throwable = t; throwable = t;
} }
try { try {
if (readWorkbookHolder.getOpcPackage() != null) { if ((readWorkbookHolder instanceof XlsxReadWorkbookHolder)
readWorkbookHolder.getOpcPackage().revert(); && ((XlsxReadWorkbookHolder)readWorkbookHolder).getOpcPackage() != null) {
((XlsxReadWorkbookHolder)readWorkbookHolder).getOpcPackage().revert();
} }
} catch (Throwable t) { } catch (Throwable t) {
throwable = t; throwable = t;
} }
try { try {
if (readWorkbookHolder.getPoifsFileSystem() != null) { if ((readWorkbookHolder instanceof XlsReadWorkbookHolder)
readWorkbookHolder.getPoifsFileSystem().close(); && ((XlsReadWorkbookHolder)readWorkbookHolder).getPoifsFileSystem() != null) {
((XlsReadWorkbookHolder)readWorkbookHolder).getPoifsFileSystem().close();
} }
} catch (Throwable t) { } catch (Throwable t) {
throwable = t; throwable = t;
@ -175,11 +181,18 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
clearEncrypt03(); clearEncrypt03();
removeThreadLocalCache();
if (throwable != null) { if (throwable != null) {
throw new ExcelAnalysisException("Can not close IO.", throwable); throw new ExcelAnalysisException("Can not close IO.", throwable);
} }
} }
private void removeThreadLocalCache() {
NumberDataFormatterUtils.removeThreadLocalCache();
DateUtils.removeThreadLocalCache();
}
private void clearEncrypt03() { private void clearEncrypt03() {
if (StringUtils.isEmpty(analysisContext.readWorkbookHolder().getPassword()) if (StringUtils.isEmpty(analysisContext.readWorkbookHolder().getPassword())
|| !ExcelTypeEnum.XLS.equals(analysisContext.readWorkbookHolder().getExcelType())) { || !ExcelTypeEnum.XLS.equals(analysisContext.readWorkbookHolder().getExcelType())) {

7
src/main/java/com/alibaba/excel/analysis/ExcelReadExecutor.java

@ -20,11 +20,6 @@ public interface ExcelReadExecutor {
/** /**
* Read the sheet. * Read the sheet.
*
* @param readSheetList
* Which sheets you need to read.
* @param readAll
* The <code>readSheetList</code> parameter is ignored, and all sheets are read.
*/ */
void execute(List<ReadSheet> readSheetList, Boolean readAll); void execute();
} }

33
src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java

@ -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();
}
}

8
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 {}

44
src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java

@ -1,8 +1,8 @@
package com.alibaba.excel.analysis.v03; package com.alibaba.excel.analysis.v03;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.HashMap;
import java.util.List; import java.util.Map;
import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder; import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder;
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; 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.HSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFRequest; import org.apache.poi.hssf.eventusermodel.HSSFRequest;
import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener; 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.hssf.record.Record;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import com.alibaba.excel.analysis.v03.handlers.BofRecordHandler; 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.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. * 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 * @author Jiaju Zhuang
*/ */
public class XlsListSheetListener implements HSSFListener { public class XlsListSheetListener implements HSSFListener {
private POIFSFileSystem poifsFileSystem; private XlsReadContext xlsReadContext;
private List<ReadSheet> sheetList; private static final Map<Short, XlsRecordHandler> XLS_RECORD_HANDLER_MAP = new HashMap<Short, XlsRecordHandler>();
private BofRecordHandler bofRecordHandler;
static {
public XlsListSheetListener(AnalysisContext analysisContext, POIFSFileSystem poifsFileSystem) { XLS_RECORD_HANDLER_MAP.put(BOFRecord.sid, new BofRecordHandler());
this.poifsFileSystem = poifsFileSystem; XLS_RECORD_HANDLER_MAP.put(BoundSheetRecord.sid, new BoundSheetRecordHandler());
sheetList = new ArrayList<ReadSheet>(); }
bofRecordHandler = new BofRecordHandler(analysisContext, sheetList, false, false);
bofRecordHandler.init(); public XlsListSheetListener(XlsReadContext xlsReadContext) {
bofRecordHandler.init(null, true); this.xlsReadContext = xlsReadContext;
xlsReadContext.xlsReadWorkbookHolder().setNeedReadSheet(Boolean.FALSE);
} }
@Override @Override
public void processRecord(Record record) { 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<ReadSheet> getSheetList() { public void execute() {
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this); MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
HSSFListener formatListener = new FormatTrackingHSSFListener(listener); HSSFListener formatListener = new FormatTrackingHSSFListener(listener);
HSSFEventFactory factory = new HSSFEventFactory(); HSSFEventFactory factory = new HSSFEventFactory();
@ -49,12 +55,10 @@ public class XlsListSheetListener implements HSSFListener {
EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener = EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener =
new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener); new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener);
request.addListenerForAllRecords(workbookBuildingListener); request.addListenerForAllRecords(workbookBuildingListener);
try { try {
factory.processWorkbookEvents(request, poifsFileSystem); factory.processWorkbookEvents(request, xlsReadContext.xlsReadWorkbookHolder().getPoifsFileSystem());
} catch (IOException e) { } catch (IOException e) {
throw new ExcelAnalysisException(e); throw new ExcelAnalysisException(e);
} }
return sheetList;
} }
} }

48
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 org.apache.poi.hssf.record.Record;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.context.xls.XlsReadContext;
/** /**
* Intercepts handle xls reads. * Intercepts handle xls reads.
* *
* @author Dan Zheng * @author Dan Zheng
*/ */
public interface XlsRecordHandler extends Comparable<XlsRecordHandler> { public interface XlsRecordHandler {
/** /**
* Which tags are supported * Whether to support
* *
* @param xlsReadContext
* @param record * @param record
* Excel analysis record * @return
* @return Which tags are supported
*/ */
boolean support(Record record); boolean support(XlsReadContext xlsReadContext, Record record);
/**
* Initialize
*/
void init();
/** /**
* Processing record * Processing record
* *
* @param xlsReadContext
* @param record * @param record
*/ */
void processRecord(Record record); void processRecord(XlsReadContext xlsReadContext, 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();
} }

241
src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java

@ -1,12 +1,9 @@
package com.alibaba.excel.analysis.v03; package com.alibaba.excel.analysis.v03;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.HashMap;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap;
import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder; import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder;
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; 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.MissingRecordAwareHSSFListener;
import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord; import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
import org.apache.poi.hssf.record.BOFRecord; 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.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.record.Record;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.record.SSTRecord;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.hssf.record.StringRecord;
import org.apache.poi.hssf.record.TextObjectRecord;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.alibaba.excel.analysis.ExcelReadExecutor; 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.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.FormulaRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.HyperlinkRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.IndexRecordHandler; import com.alibaba.excel.analysis.v03.handlers.IndexRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.LabelRecordHandler; 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.NoteRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.NumberRecordHandler; 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.RkRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.SstRecordHandler; import com.alibaba.excel.analysis.v03.handlers.SstRecordHandler;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.analysis.v03.handlers.StringRecordHandler;
import com.alibaba.excel.enums.CellDataTypeEnum; 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.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.exception.ExcelAnalysisStopException;
import com.alibaba.excel.read.listener.event.EachRowAnalysisFinishEvent;
import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder; import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder;
import com.alibaba.excel.util.CollectionUtils;
/** /**
* /** * A text extractor for Excel files. * * /** * A text extractor for Excel files. *
@ -60,168 +77,90 @@ import com.alibaba.excel.util.CollectionUtils;
*/ */
public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor {
private static final Logger LOGGER = LoggerFactory.getLogger(XlsSaxAnalyser.class); private static final Logger LOGGER = LoggerFactory.getLogger(XlsSaxAnalyser.class);
private static final short DUMMY_RECORD_SID = -1;
private POIFSFileSystem poifsFileSystem; private XlsReadContext xlsReadContext;
private Boolean readAll; private static final Map<Short, XlsRecordHandler> XLS_RECORD_HANDLER_MAP = new HashMap<Short, XlsRecordHandler>(32);
private List<ReadSheet> readSheetList;
private int lastRowNumber; static {
private int lastColumnNumber; XLS_RECORD_HANDLER_MAP.put(BlankRecord.sid, new BlankRecordHandler());
/** XLS_RECORD_HANDLER_MAP.put(BOFRecord.sid, new BofRecordHandler());
* For parsing Formulas XLS_RECORD_HANDLER_MAP.put(BoolErrRecord.sid, new BoolErrRecordHandler());
*/ XLS_RECORD_HANDLER_MAP.put(BoundSheetRecord.sid, new BoundSheetRecordHandler());
private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener; XLS_RECORD_HANDLER_MAP.put(DUMMY_RECORD_SID, new DummyRecordHandler());
private FormatTrackingHSSFListener formatListener; XLS_RECORD_HANDLER_MAP.put(EOFRecord.sid, new EofRecordHandler());
private Map<Integer, CellData> records; XLS_RECORD_HANDLER_MAP.put(FormulaRecord.sid, new FormulaRecordHandler());
private List<ReadSheet> sheets; XLS_RECORD_HANDLER_MAP.put(HyperlinkRecord.sid, new HyperlinkRecordHandler());
private HSSFWorkbook stubWorkbook; XLS_RECORD_HANDLER_MAP.put(IndexRecord.sid, new IndexRecordHandler());
private List<XlsRecordHandler> recordHandlers = new ArrayList<XlsRecordHandler>(); XLS_RECORD_HANDLER_MAP.put(LabelRecord.sid, new LabelRecordHandler());
private AnalysisContext analysisContext; XLS_RECORD_HANDLER_MAP.put(LabelSSTRecord.sid, new LabelSstRecordHandler());
XLS_RECORD_HANDLER_MAP.put(MergeCellsRecord.sid, new MergeCellsRecordHandler());
public XlsSaxAnalyser(AnalysisContext context, POIFSFileSystem poifsFileSystem) { XLS_RECORD_HANDLER_MAP.put(NoteRecord.sid, new NoteRecordHandler());
this.analysisContext = context; XLS_RECORD_HANDLER_MAP.put(NumberRecord.sid, new NumberRecordHandler());
this.records = new LinkedHashMap<Integer, CellData>(); XLS_RECORD_HANDLER_MAP.put(ObjRecord.sid, new ObjRecordHandler());
this.poifsFileSystem = poifsFileSystem; XLS_RECORD_HANDLER_MAP.put(RKRecord.sid, new RkRecordHandler());
analysisContext.readWorkbookHolder().setPoifsFileSystem(poifsFileSystem); 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());
}
public XlsSaxAnalyser(XlsReadContext xlsReadContext) {
this.xlsReadContext = xlsReadContext;
} }
@Override @Override
public List<ReadSheet> sheetList() { public List<ReadSheet> sheetList() {
if (sheets == null) { try {
LOGGER.warn("Getting the 'sheetList' before reading will cause the file to be read twice."); if (xlsReadContext.readWorkbookHolder().getActualSheetDataList() == null) {
XlsListSheetListener xlsListSheetListener = new XlsListSheetListener(analysisContext, poifsFileSystem); new XlsListSheetListener(xlsReadContext).execute();
sheets = xlsListSheetListener.getSheetList(); }
} catch (ExcelAnalysisStopException e) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Custom stop!");
} }
return sheets; }
return xlsReadContext.readWorkbookHolder().getActualSheetDataList();
} }
@Override @Override
public void execute(List<ReadSheet> readSheetList, Boolean readAll) { public void execute() {
this.readAll = readAll; XlsReadWorkbookHolder xlsReadWorkbookHolder = xlsReadContext.xlsReadWorkbookHolder();
this.readSheetList = readSheetList;
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this); MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
formatListener = new FormatTrackingHSSFListener(listener); xlsReadWorkbookHolder.setFormatTrackingHSSFListener(new FormatTrackingHSSFListener(listener));
workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener); EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener =
if (workbookBuildingListener != null && stubWorkbook == null) { new EventWorkbookBuilder.SheetRecordCollectingListener(
stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook(); xlsReadWorkbookHolder.getFormatTrackingHSSFListener());
} xlsReadWorkbookHolder.setHssfWorkbook(workbookBuildingListener.getStubHSSFWorkbook());
init();
HSSFEventFactory factory = new HSSFEventFactory(); HSSFEventFactory factory = new HSSFEventFactory();
HSSFRequest request = new HSSFRequest(); HSSFRequest request = new HSSFRequest();
request.addListenerForAllRecords(formatListener); request.addListenerForAllRecords(xlsReadWorkbookHolder.getFormatTrackingHSSFListener());
try { try {
factory.processWorkbookEvents(request, poifsFileSystem); factory.processWorkbookEvents(request, xlsReadWorkbookHolder.getPoifsFileSystem());
} catch (IOException e) { } catch (IOException e) {
throw new ExcelAnalysisException(e); throw new ExcelAnalysisException(e);
} }
// Sometimes tables lack the end record of the last column // Sometimes tables lack the end record of the last column
if (!records.isEmpty()) { if (!xlsReadContext.xlsReadSheetHolder().getCellMap().isEmpty()) {
endRow(); // Forge a termination data
processRecord(new LastCellOfRowDummyRecord(xlsReadContext.xlsReadSheetHolder().getRowIndex() + 1, -1));
} }
} }
private void init() {
lastRowNumber = 0;
lastColumnNumber = 0;
records = new LinkedHashMap<Integer, CellData>();
buildXlsRecordHandlers();
}
@Override @Override
public void processRecord(Record record) { public void processRecord(Record record) {
// Not data from the current sheet XlsRecordHandler handler = XLS_RECORD_HANDLER_MAP.get(record.getSid());
if (ignoreRecord(record)) { if (handler == null) {
return; return;
} }
int thisRow = -1; boolean ignoreRecord = (handler instanceof IgnorableXlsRecordHandler)
int thisColumn = -1; && xlsReadContext.xlsReadSheetHolder() != null && xlsReadContext.xlsReadSheetHolder().getIgnoreRecord();
CellData cellData = null; if (ignoreRecord) {
for (XlsRecordHandler handler : this.recordHandlers) { // No need to read the current sheet
if (handler.support(record)) { return;
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();
}
}
private void endRow() {
if (lastColumnNumber == -1) {
lastColumnNumber = 0;
}
analysisContext.readRowHolder(
new ReadRowHolder(lastRowNumber, analysisContext.readSheetHolder().getGlobalConfiguration()));
analysisContext.readSheetHolder().notifyEndOneRow(new EachRowAnalysisFinishEvent(records), analysisContext);
records.clear();
lastColumnNumber = -1;
} }
if (!handler.support(xlsReadContext, record)) {
private void buildXlsRecordHandlers() { return;
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<ReadSheet>();
recordHandlers.add(new BofRecordHandler(analysisContext, sheets, false, true));
} else {
recordHandlers.add(new BofRecordHandler(analysisContext, sheets, true, true));
} }
recordHandlers.add(new FormulaRecordHandler(stubWorkbook, formatListener)); handler.processRecord(xlsReadContext, record);
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);
}
}
}
} }

19
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;
}
}

47
src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java

@ -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;
}
}

23
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()));
}
}

121
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.BoundSheetRecord;
import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.Record;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; import com.alibaba.excel.context.xls.XlsReadContext;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.exception.ExcelAnalysisStopException;
import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder;
import com.alibaba.excel.util.SheetUtils; import com.alibaba.excel.util.SheetUtils;
/** /**
@ -18,91 +19,55 @@ import com.alibaba.excel.util.SheetUtils;
* @author Dan Zheng * @author Dan Zheng
*/ */
public class BofRecordHandler extends AbstractXlsRecordHandler { public class BofRecordHandler extends AbstractXlsRecordHandler {
private List<BoundSheetRecord> boundSheetRecords = new ArrayList<BoundSheetRecord>();
private BoundSheetRecord[] orderedBsrs;
private int sheetIndex;
private List<ReadSheet> sheets;
private Boolean readAll;
private List<ReadSheet> readSheetList;
private AnalysisContext context;
private boolean alreadyInit;
private boolean needInitSheet;
public BofRecordHandler(AnalysisContext context, List<ReadSheet> 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 @Override
public void processRecord(Record record) { public void processRecord(XlsReadContext xlsReadContext, Record record) {
if (record.getSid() == BoundSheetRecord.sid) {
boundSheetRecords.add((BoundSheetRecord)record);
} else if (record.getSid() == BOFRecord.sid) {
BOFRecord br = (BOFRecord)record; BOFRecord br = (BOFRecord)record;
if (br.getType() == BOFRecord.TYPE_WORKSHEET) { XlsReadWorkbookHolder xlsReadWorkbookHolder = xlsReadContext.xlsReadWorkbookHolder();
if (orderedBsrs == null) { if (br.getType() == BOFRecord.TYPE_WORKBOOK) {
orderedBsrs = BoundSheetRecord.orderByBofPosition(boundSheetRecords); xlsReadWorkbookHolder.setReadSheetIndex(null);
} return;
String sheetName = orderedBsrs[sheetIndex].getSheetname(); }
// Find the currently read sheet if (br.getType() != BOFRecord.TYPE_WORKSHEET) {
ReadSheet readSheet = null; return;
if (!alreadyInit) { }
readSheet = new ReadSheet(sheetIndex, sheetName); // Init read sheet Data
sheets.add(readSheet); initReadSheetDataList(xlsReadWorkbookHolder);
} Integer readSheetIndex = xlsReadWorkbookHolder.getReadSheetIndex();
if (needInitSheet) { if (readSheetIndex == null) {
if (readSheet == null) { readSheetIndex = 0;
for (ReadSheet sheet : sheets) { xlsReadWorkbookHolder.setReadSheetIndex(readSheetIndex);
if (sheet.getSheetNo() == sheetIndex) { }
readSheet = sheet; ReadSheet readSheet = xlsReadWorkbookHolder.getActualSheetDataList().get(readSheetIndex);
break;
}
}
}
assert readSheet != null : "Can't find the sheet."; assert readSheet != null : "Can't find the sheet.";
context.readWorkbookHolder().setIgnoreRecord03(Boolean.TRUE);
// Copy the parameter to the current sheet // Copy the parameter to the current sheet
readSheet = SheetUtils.match(readSheet, readSheetList, readAll, readSheet = SheetUtils.match(readSheet, xlsReadContext);
context.readWorkbookHolder().getGlobalConfiguration());
if (readSheet != null) { if (readSheet != null) {
if (readSheet.getSheetNo() != 0 && context.readSheetHolder() != null) { xlsReadContext.currentSheet(readSheet);
// Prompt for the end of the previous form read xlsReadContext.xlsReadSheetHolder().setIgnoreRecord(Boolean.FALSE);
context.readSheetHolder().notifyAfterAllAnalysed(context); } else {
} xlsReadContext.xlsReadSheetHolder().setIgnoreRecord(Boolean.TRUE);
context.currentSheet(readSheet);
context.readWorkbookHolder().setIgnoreRecord03(Boolean.FALSE);
}
}
sheetIndex++;
}
}
}
@Override
public void init() {
sheetIndex = 0;
orderedBsrs = null;
boundSheetRecords.clear();
if (!alreadyInit) {
sheets.clear();
} }
// Go read the next one
xlsReadWorkbookHolder.setReadSheetIndex(xlsReadWorkbookHolder.getReadSheetIndex() + 1);
} }
public void init(List<ReadSheet> readSheetList, Boolean readAll) { private void initReadSheetDataList(XlsReadWorkbookHolder xlsReadWorkbookHolder) {
this.readSheetList = readSheetList; if (xlsReadWorkbookHolder.getActualSheetDataList() != null) {
this.readAll = readAll; return;
}
BoundSheetRecord[] boundSheetRecords =
BoundSheetRecord.orderByBofPosition(xlsReadWorkbookHolder.getBoundSheetRecordList());
List<ReadSheet> readSheetDataList = new ArrayList<ReadSheet>();
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.");
} }
@Override
public int getOrder() {
return 0;
} }
} }

25
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);
}
}

21
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);
}
}

41
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<Integer, Cell>());
xlsReadSheetHolder.setTempRowType(RowTypeEnum.EMPTY);
} else if (record instanceof MissingCellDummyRecord) {
MissingCellDummyRecord mcdr = (MissingCellDummyRecord)record;
xlsReadSheetHolder.getCellMap().put(mcdr.getColumn(),
CellData.newEmptyInstance(mcdr.getRow(), mcdr.getColumn()));
}
}
}

21
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);
}
}
}

106
src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java

@ -1,19 +1,20 @@
package com.alibaba.excel.analysis.v03.handlers; package com.alibaba.excel.analysis.v03.handlers;
import java.math.BigDecimal; 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.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.FormulaRecord; import org.apache.poi.hssf.record.FormulaRecord;
import org.apache.poi.hssf.record.Record; 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.apache.poi.ss.usermodel.CellType;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.Cell;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
/** /**
@ -21,96 +22,59 @@ import com.alibaba.excel.metadata.CellData;
* *
* @author Dan Zheng * @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 Logger LOGGER = LoggerFactory.getLogger(FormulaRecordHandler.class);
private static final String ERROR = "#VALUE!"; 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 @Override
public void processRecord(Record record) { public void processRecord(XlsReadContext xlsReadContext, Record record) {
if (record.getSid() == FormulaRecord.sid) {
FormulaRecord frec = (FormulaRecord)record; FormulaRecord frec = (FormulaRecord)record;
Map<Integer, Cell> cellMap = xlsReadContext.xlsReadSheetHolder().getCellMap();
this.row = frec.getRow(); CellData tempCellData = new CellData();
this.column = frec.getColumn(); tempCellData.setRowIndex(frec.getRow());
tempCellData.setColumnIndex((int)frec.getColumn());
CellType cellType = CellType.forInt(frec.getCachedResultType()); CellType cellType = CellType.forInt(frec.getCachedResultType());
String formulaValue = null; String formulaValue = null;
try { try {
formulaValue = HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()); formulaValue = HSSFFormulaParser.toFormulaString(xlsReadContext.xlsReadWorkbookHolder().getHssfWorkbook(),
frec.getParsedExpression());
} catch (Exception e) { } catch (Exception e) {
LOGGER.warn("Get formula value error.{}", e.getMessage()); LOGGER.debug("Get formula value error.", e);
} }
tempCellData.setFormula(Boolean.TRUE);
tempCellData.setFormulaValue(formulaValue);
switch (cellType) { switch (cellType) {
case STRING: case STRING:
// Formula result is a string // Formula result is a string
// This is stored in the next record // This is stored in the next record
outputNextStringRecord = true; tempCellData.setType(CellDataTypeEnum.STRING);
nextRow = frec.getRow(); xlsReadContext.xlsReadSheetHolder().setTempCellData(tempCellData);
nextColumn = frec.getColumn();
tempCellData = new CellData(CellDataTypeEnum.STRING);
tempCellData.setFormula(Boolean.TRUE);
tempCellData.setFormulaValue(formulaValue);
break; break;
case NUMERIC: case NUMERIC:
this.cellData = new CellData(BigDecimal.valueOf(frec.getValue())); tempCellData.setType(CellDataTypeEnum.NUMBER);
this.cellData.setFormula(Boolean.TRUE); tempCellData.setNumberValue(BigDecimal.valueOf(frec.getValue()));
this.cellData.setFormulaValue(formulaValue); 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; break;
case ERROR: case ERROR:
this.cellData = new CellData(CellDataTypeEnum.ERROR); tempCellData.setType(CellDataTypeEnum.ERROR);
this.cellData.setStringValue(ERROR); tempCellData.setStringValue(ERROR);
this.cellData.setFormula(Boolean.TRUE); cellMap.put((int)frec.getColumn(), tempCellData);
this.cellData.setFormulaValue(formulaValue);
break; break;
case BOOLEAN: case BOOLEAN:
this.cellData = new CellData(frec.getCachedBooleanValue()); tempCellData.setType(CellDataTypeEnum.BOOLEAN);
this.cellData.setFormula(Boolean.TRUE); tempCellData.setBooleanValue(frec.getCachedBooleanValue());
this.cellData.setFormulaValue(formulaValue); cellMap.put((int)frec.getColumn(), tempCellData);
break; break;
default: default:
this.cellData = new CellData(CellDataTypeEnum.EMPTY); tempCellData.setType(CellDataTypeEnum.EMPTY);
this.cellData.setFormula(Boolean.TRUE); cellMap.put((int)frec.getColumn(), tempCellData);
this.cellData.setFormulaValue(formulaValue);
break; 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;
}
}
}
@Override
public void init() {
this.nextRow = 0;
this.nextColumn = 0;
}
@Override
public int getOrder() {
return 0;
} }
} }

30
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);
}
}

32
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.IndexRecord;
import org.apache.poi.hssf.record.Record; 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.AnalysisContext; import com.alibaba.excel.context.xls.XlsReadContext;
/** /**
* Record handler * Record handler
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
public class IndexRecordHandler extends AbstractXlsRecordHandler { public class IndexRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
private AnalysisContext context;
public IndexRecordHandler(AnalysisContext context) {
this.context = context;
}
@Override
public boolean support(Record record) {
return record instanceof IndexRecord;
}
@Override
public void init() {}
@Override @Override
public void processRecord(Record record) { public void processRecord(XlsReadContext xlsReadContext, Record record) {
if (context.readSheetHolder() == null) { if (xlsReadContext.readSheetHolder() == null) {
return; return;
} }
context.readSheetHolder().setApproximateTotalRowNumber(((IndexRecord)record).getLastRowAdd1()); xlsReadContext.readSheetHolder().setApproximateTotalRowNumber(((IndexRecord)record).getLastRowAdd1());
}
@Override
public int getOrder() {
return 1;
} }
} }

31
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.LabelRecord;
import org.apache.poi.hssf.record.Record; 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; import com.alibaba.excel.metadata.CellData;
/** /**
@ -11,27 +13,16 @@ import com.alibaba.excel.metadata.CellData;
* *
* @author Dan Zheng * @author Dan Zheng
*/ */
public class LabelRecordHandler extends AbstractXlsRecordHandler { public class LabelRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
@Override @Override
public boolean support(Record record) { public void processRecord(XlsReadContext xlsReadContext, Record record) {
return LabelRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
LabelRecord lrec = (LabelRecord)record; LabelRecord lrec = (LabelRecord)record;
this.row = lrec.getRow(); String data = lrec.getValue();
this.column = lrec.getColumn(); if (data != null && xlsReadContext.currentReadHolder().globalConfiguration().getAutoTrim()) {
this.cellData = new CellData(lrec.getValue()); data = data.trim();
} }
xlsReadContext.xlsReadSheetHolder().getCellMap().put((int)lrec.getColumn(),
@Override CellData.newInstance(data, lrec.getRow(), (int)lrec.getColumn()));
public void init() { xlsReadContext.xlsReadSheetHolder().setTempRowType(RowTypeEnum.DATA);
}
@Override
public int getOrder() {
return 0;
} }
} }

42
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<Integer, Cell> 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);
}
}

35
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);
}
}
}

38
src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java

@ -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;
}
}

33
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.NoteRecord;
import org.apache.poi.hssf.record.Record; 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.enums.CellDataTypeEnum; import com.alibaba.excel.context.xls.XlsReadContext;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.metadata.CellExtra;
/** /**
* Record handler * Record handler
* *
* @author Dan Zheng * @author Dan Zheng
*/ */
public class NoteRecordHandler extends AbstractXlsRecordHandler { public class NoteRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
@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);
}
@Override @Override
public void init() { public boolean support(XlsReadContext xlsReadContext, Record record) {
return xlsReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.COMMENT);
} }
@Override @Override
public int getOrder() { public void processRecord(XlsReadContext xlsReadContext, Record record) {
return 0; 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);
} }
} }

45
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 java.math.BigDecimal;
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
import org.apache.poi.hssf.record.NumberRecord; import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.Record; 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; import com.alibaba.excel.metadata.CellData;
/** /**
@ -14,35 +16,18 @@ import com.alibaba.excel.metadata.CellData;
* *
* @author Dan Zheng * @author Dan Zheng
*/ */
public class NumberRecordHandler extends AbstractXlsRecordHandler { public class NumberRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
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() {
}
@Override @Override
public int getOrder() { public void processRecord(XlsReadContext xlsReadContext, Record record) {
return 0; 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);
} }
} }

30
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;
}
}
}
}

30
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.RKRecord;
import org.apache.poi.hssf.record.Record; 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.enums.CellDataTypeEnum; import com.alibaba.excel.context.xls.XlsReadContext;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
/** /**
@ -12,28 +12,12 @@ import com.alibaba.excel.metadata.CellData;
* *
* @author Dan Zheng * @author Dan Zheng
*/ */
public class RkRecordHandler extends AbstractXlsRecordHandler { public class RkRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
@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() {
}
@Override @Override
public int getOrder() { public void processRecord(XlsReadContext xlsReadContext, Record record) {
return 0; RKRecord re = (RKRecord)record;
xlsReadContext.xlsReadSheetHolder().getCellMap().put((int)re.getColumn(),
CellData.newEmptyInstance(re.getRow(), (int)re.getColumn()));
} }
} }

41
src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java

@ -1,49 +1,20 @@
package com.alibaba.excel.analysis.v03.handlers; 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.Record;
import org.apache.poi.hssf.record.SSTRecord; import org.apache.poi.hssf.record.SSTRecord;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.cache.XlsCache;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.context.xls.XlsReadContext;
/** /**
* Record handler * Record handler
* *
* @author Dan Zheng * @author Dan Zheng
*/ */
public class SstRecordHandler extends AbstractXlsRecordHandler { public class SstRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler {
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() {
}
@Override @Override
public int getOrder() { public void processRecord(XlsReadContext xlsReadContext, Record record) {
return 0; xlsReadContext.readWorkbookHolder().setReadCache(new XlsCache((SSTRecord)record));
} }
} }

35
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);
}
}

38
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);
}
}

37
src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java

@ -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);
}

27
src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java

@ -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<XlsxCellHandler> buildCellHandlers(AnalysisContext analysisContext, StylesTable stylesTable) {
List<XlsxCellHandler> result = new ArrayList<XlsxCellHandler>();
result.add(new CountRowCellHandler(analysisContext));
DefaultCellHandler defaultCellHandler = new DefaultCellHandler(analysisContext, stylesTable);
result.add(defaultCellHandler);
result.add(new ProcessResultCellHandler(analysisContext, defaultCellHandler));
return result;
}
}

55
src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java

@ -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<XlsxCellHandler> 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);
}
}
}

33
src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java

@ -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<Integer, CellData> getCurRowContent();
}

113
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.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess; import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.openxml4j.opc.PackagePart; 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.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.apache.poi.xssf.usermodel.XSSFRelation;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr;
@ -26,37 +28,40 @@ import org.xml.sax.InputSource;
import org.xml.sax.XMLReader; import org.xml.sax.XMLReader;
import com.alibaba.excel.analysis.ExcelReadExecutor; 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.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.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.metadata.ReadSheet; 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.CollectionUtils;
import com.alibaba.excel.util.FileUtils; import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.util.SheetUtils; import com.alibaba.excel.util.SheetUtils;
import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.util.StringUtils;
/** /**
*
* @author jipengfei * @author jipengfei
*/ */
public class XlsxSaxAnalyser implements ExcelReadExecutor { public class XlsxSaxAnalyser implements ExcelReadExecutor {
private AnalysisContext analysisContext; private XlsxReadContext xlsxReadContext;
private List<ReadSheet> sheetList; private List<ReadSheet> sheetList;
private Map<Integer, InputStream> sheetMap; private Map<Integer, InputStream> sheetMap;
/** /**
* Current style information * excel comments key: sheetNo value: CommentsTable
*/ */
private StylesTable stylesTable; private Map<Integer, CommentsTable> commentsTableMap;
public XlsxSaxAnalyser(AnalysisContext analysisContext, InputStream decryptedStream) throws Exception { public XlsxSaxAnalyser(XlsxReadContext xlsxReadContext, InputStream decryptedStream) throws Exception {
this.analysisContext = analysisContext; this.xlsxReadContext = xlsxReadContext;
// Initialize cache // Initialize cache
ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder(); XlsxReadWorkbookHolder xlsxReadWorkbookHolder = xlsxReadContext.xlsxReadWorkbookHolder();
OPCPackage pkg = readOpcPackage(readWorkbookHolder, decryptedStream); OPCPackage pkg = readOpcPackage(xlsxReadWorkbookHolder, decryptedStream);
readWorkbookHolder.setOpcPackage(pkg); xlsxReadWorkbookHolder.setOpcPackage(pkg);
ArrayList<PackagePart> packageParts = pkg.getPartsByContentType(XSSFRelation.SHARED_STRINGS.getContentType()); ArrayList<PackagePart> packageParts = pkg.getPartsByContentType(XSSFRelation.SHARED_STRINGS.getContentType());
@ -64,18 +69,19 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
PackagePart sharedStringsTablePackagePart = packageParts.get(0); PackagePart sharedStringsTablePackagePart = packageParts.get(0);
// Specify default cache // Specify default cache
defaultReadCache(readWorkbookHolder, sharedStringsTablePackagePart); defaultReadCache(xlsxReadWorkbookHolder, sharedStringsTablePackagePart);
// Analysis sharedStringsTable.xml // Analysis sharedStringsTable.xml
analysisSharedStringsTable(sharedStringsTablePackagePart.getInputStream(), readWorkbookHolder); analysisSharedStringsTable(sharedStringsTablePackagePart.getInputStream(), xlsxReadWorkbookHolder);
} }
XSSFReader xssfReader = new XSSFReader(pkg); XSSFReader xssfReader = new XSSFReader(pkg);
analysisUse1904WindowDate(xssfReader, readWorkbookHolder); analysisUse1904WindowDate(xssfReader, xlsxReadWorkbookHolder);
stylesTable = xssfReader.getStylesTable(); xlsxReadWorkbookHolder.setStylesTable(xssfReader.getStylesTable());
sheetList = new ArrayList<ReadSheet>(); sheetList = new ArrayList<ReadSheet>();
sheetMap = new HashMap<Integer, InputStream>(); sheetMap = new HashMap<Integer, InputStream>();
commentsTableMap = new HashMap<Integer, CommentsTable>();
XSSFReader.SheetIterator ite = (XSSFReader.SheetIterator)xssfReader.getSheetsData(); XSSFReader.SheetIterator ite = (XSSFReader.SheetIterator)xssfReader.getSheetsData();
int index = 0; int index = 0;
if (!ite.hasNext()) { if (!ite.hasNext()) {
@ -85,19 +91,26 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
InputStream inputStream = ite.next(); InputStream inputStream = ite.next();
sheetList.add(new ReadSheet(index, ite.getSheetName())); sheetList.add(new ReadSheet(index, ite.getSheetName()));
sheetMap.put(index, inputStream); sheetMap.put(index, inputStream);
if (xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.COMMENT)) {
CommentsTable commentsTable = ite.getSheetComments();
if (null != commentsTable) {
commentsTableMap.put(index, commentsTable);
}
}
index++; index++;
} }
} }
private void defaultReadCache(ReadWorkbookHolder readWorkbookHolder, PackagePart sharedStringsTablePackagePart) { private void defaultReadCache(XlsxReadWorkbookHolder xlsxReadWorkbookHolder,
ReadCache readCache = readWorkbookHolder.getReadCacheSelector().readCache(sharedStringsTablePackagePart); PackagePart sharedStringsTablePackagePart) {
readWorkbookHolder.setReadCache(readCache); ReadCache readCache = xlsxReadWorkbookHolder.getReadCacheSelector().readCache(sharedStringsTablePackagePart);
readCache.init(analysisContext); xlsxReadWorkbookHolder.setReadCache(readCache);
readCache.init(xlsxReadContext);
} }
private void analysisUse1904WindowDate(XSSFReader xssfReader, ReadWorkbookHolder readWorkbookHolder) private void analysisUse1904WindowDate(XSSFReader xssfReader, XlsxReadWorkbookHolder xlsxReadWorkbookHolder)
throws Exception { throws Exception {
if (readWorkbookHolder.globalConfiguration().getUse1904windowing() != null) { if (xlsxReadWorkbookHolder.globalConfiguration().getUse1904windowing() != null) {
return; return;
} }
InputStream workbookXml = xssfReader.getWorkbookData(); InputStream workbookXml = xssfReader.getWorkbookData();
@ -105,38 +118,38 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
CTWorkbook wb = ctWorkbook.getWorkbook(); CTWorkbook wb = ctWorkbook.getWorkbook();
CTWorkbookPr prefix = wb.getWorkbookPr(); CTWorkbookPr prefix = wb.getWorkbookPr();
if (prefix != null && prefix.getDate1904()) { if (prefix != null && prefix.getDate1904()) {
readWorkbookHolder.getGlobalConfiguration().setUse1904windowing(Boolean.TRUE); xlsxReadWorkbookHolder.getGlobalConfiguration().setUse1904windowing(Boolean.TRUE);
} else { } else {
readWorkbookHolder.getGlobalConfiguration().setUse1904windowing(Boolean.FALSE); xlsxReadWorkbookHolder.getGlobalConfiguration().setUse1904windowing(Boolean.FALSE);
} }
} }
private void analysisSharedStringsTable(InputStream sharedStringsTableInputStream, private void analysisSharedStringsTable(InputStream sharedStringsTableInputStream,
ReadWorkbookHolder readWorkbookHolder) throws Exception { XlsxReadWorkbookHolder xlsxReadWorkbookHolder) throws Exception {
ContentHandler handler = new SharedStringsTableHandler(readWorkbookHolder.getReadCache()); ContentHandler handler = new SharedStringsTableHandler(xlsxReadWorkbookHolder.getReadCache());
parseXmlSource(sharedStringsTableInputStream, handler); 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 { throws Exception {
if (decryptedStream == null && readWorkbookHolder.getFile() != null) { if (decryptedStream == null && xlsxReadWorkbookHolder.getFile() != null) {
return OPCPackage.open(readWorkbookHolder.getFile()); return OPCPackage.open(xlsxReadWorkbookHolder.getFile());
} }
if (readWorkbookHolder.getMandatoryUseInputStream()) { if (xlsxReadWorkbookHolder.getMandatoryUseInputStream()) {
if (decryptedStream != null) { if (decryptedStream != null) {
return OPCPackage.open(decryptedStream); return OPCPackage.open(decryptedStream);
} else { } else {
return OPCPackage.open(readWorkbookHolder.getInputStream()); return OPCPackage.open(xlsxReadWorkbookHolder.getInputStream());
} }
} }
File readTempFile = FileUtils.createCacheTmpFile(); File readTempFile = FileUtils.createCacheTmpFile();
readWorkbookHolder.setTempFile(readTempFile); xlsxReadWorkbookHolder.setTempFile(readTempFile);
File tempFile = new File(readTempFile.getPath(), UUID.randomUUID().toString() + ".xlsx"); File tempFile = new File(readTempFile.getPath(), UUID.randomUUID().toString() + ".xlsx");
if (decryptedStream != null) { if (decryptedStream != null) {
FileUtils.writeToFile(tempFile, decryptedStream); FileUtils.writeToFile(tempFile, decryptedStream);
} else { } else {
FileUtils.writeToFile(tempFile, readWorkbookHolder.getInputStream()); FileUtils.writeToFile(tempFile, xlsxReadWorkbookHolder.getInputStream());
} }
return OPCPackage.open(tempFile, PackageAccess.READ); return OPCPackage.open(tempFile, PackageAccess.READ);
} }
@ -150,7 +163,7 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
InputSource inputSource = new InputSource(inputStream); InputSource inputSource = new InputSource(inputStream);
try { try {
SAXParserFactory saxFactory; SAXParserFactory saxFactory;
String xlsxSAXParserFactoryName = analysisContext.readWorkbookHolder().getXlsxSAXParserFactoryName(); String xlsxSAXParserFactoryName = xlsxReadContext.xlsxReadWorkbookHolder().getSaxParserFactoryName();
if (StringUtils.isEmpty(xlsxSAXParserFactoryName)) { if (StringUtils.isEmpty(xlsxSAXParserFactoryName)) {
saxFactory = SAXParserFactory.newInstance(); saxFactory = SAXParserFactory.newInstance();
} else { } else {
@ -180,16 +193,34 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
} }
@Override @Override
public void execute(List<ReadSheet> readSheetList, Boolean readAll) { public void execute() {
for (ReadSheet readSheet : sheetList) { for (ReadSheet readSheet : sheetList) {
readSheet = SheetUtils.match(readSheet, readSheetList, readAll, readSheet = SheetUtils.match(readSheet, xlsxReadContext);
analysisContext.readWorkbookHolder().getGlobalConfiguration());
if (readSheet != null) { if (readSheet != null) {
analysisContext.currentSheet(readSheet); xlsxReadContext.currentSheet(readSheet);
parseXmlSource(sheetMap.get(readSheet.getSheetNo()), new XlsxRowHandler(analysisContext, stylesTable)); parseXmlSource(sheetMap.get(readSheet.getSheetNo()), new XlsxRowHandler(xlsxReadContext));
// Read comments
readComments(readSheet);
// The last sheet is read // 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<CellAddress, XSSFComment> 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);
} }
} }
} }

66
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);
}

32
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) {
}
}

32
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);
}
}

23
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());
}
}

57
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()));
}
}

34
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:
}
}
}

42
src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java

@ -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) {
}
}

23
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));
}
}

184
src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java

@ -1,184 +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<String> currentTagDeque = new LinkedList<String>();
private int curCol;
private Map<Integer, CellData> curRowContent = new LinkedHashMap<Integer, CellData>();
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<Integer, CellData>();
}
@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));
// 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<Integer, CellData> getCurRowContent() {
return curRowContent;
}
}

35
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);
}
}

34
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);
}
}

48
src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java

@ -1,48 +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;
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) {
analysisContext.readRowHolder(
new ReadRowHolder(PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.POSITION)),
analysisContext.readSheetHolder().getGlobalConfiguration()));
}
@Override
public void endHandle(String name) {
analysisContext.readSheetHolder()
.notifyEndOneRow(new EachRowAnalysisFinishEvent(rowResultHandler.getCurRowContent()), analysisContext);
rowResultHandler.clearResult();
}
}

51
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<Integer, Cell>()));
xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext);
xlsxReadSheetHolder.setColumnIndex(null);
xlsxReadSheetHolder.setCellMap(new LinkedHashMap<Integer, Cell>());
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<Integer, Cell>());
}
}

54
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);
}

2
src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java → 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.Attributes;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;

93
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<String, XlsxTagHandler> XLSX_CELL_HANDLER_MAP = new HashMap<String, XlsxTagHandler>(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();
}
}

89
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;
}

31
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;
}

159
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 <code>true</code> 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 <i>Note: Ensure Foreground color is set prior to background color.</i>
*
* @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;
}

89
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;
}

159
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 <code>true</code> 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 <i>Note: Ensure Foreground color is set prior to background color.</i>
*
* @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;
}

45
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;
}

37
src/main/java/com/alibaba/excel/cache/XlsCache.java vendored

@ -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() {}
}

379
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.
*
* <p>
* If it is not Chinese, it is recommended to directly modify the builtinFormats, which will better support
* internationalization in the future.
*
* <p>
* 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;
}
}

52
src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java

@ -4,22 +4,54 @@ package com.alibaba.excel.constant;
* @author jipengfei * @author jipengfei
*/ */
public class ExcelXmlConstants { public class ExcelXmlConstants {
public static final String DIMENSION = "dimension"; public static final String DIMENSION_TAG = "dimension";
public static final String DIMENSION_REF = "ref";
public static final String POSITION = "r";
public static final String ROW_TAG = "row"; 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_FORMULA_TAG = "f";
public static final String CELL_VALUE_TAG = "v"; public static final String CELL_VALUE_TAG = "v";
/** /**
* When the data is "inlineStr" his tag is "t" * When the data is "inlineStr" his tag is "t"
*/ */
public static final String CELL_INLINE_STRING_VALUE_TAG = "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 = ":";
} }

24
src/main/java/com/alibaba/excel/context/AnalysisContext.java

@ -1,8 +1,8 @@
package com.alibaba.excel.context; package com.alibaba.excel.context;
import java.io.InputStream; import java.io.InputStream;
import java.util.List;
import com.alibaba.excel.analysis.ExcelReadExecutor;
import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.read.metadata.ReadSheet; 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.ReadRowHolder;
import com.alibaba.excel.read.metadata.holder.ReadSheetHolder; import com.alibaba.excel.read.metadata.holder.ReadSheetHolder;
import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
import com.alibaba.excel.read.processor.AnalysisEventProcessor;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
/** /**
@ -70,6 +71,27 @@ public interface AnalysisContext {
*/ */
Object getCustom(); Object getCustom();
/**
* Event processor
*
* @return
*/
AnalysisEventProcessor analysisEventProcessor();
/**
* Data that the customer needs to read
*
* @return
*/
List<ReadSheet> readSheetList();
/**
* Data that the customer needs to read
*
* @param readSheetList
*/
void readSheetList(List<ReadSheet> readSheetList);
/** /**
* get current sheet * get current sheet
* *

51
src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java

@ -1,6 +1,7 @@
package com.alibaba.excel.context; package com.alibaba.excel.context;
import java.io.InputStream; import java.io.InputStream;
import java.util.List;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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.ReadRowHolder;
import com.alibaba.excel.read.metadata.holder.ReadSheetHolder; import com.alibaba.excel.read.metadata.holder.ReadSheetHolder;
import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; 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; import com.alibaba.excel.support.ExcelTypeEnum;
/** /**
@ -37,13 +44,27 @@ public class AnalysisContextImpl implements AnalysisContext {
* Configuration of currently operated cell * Configuration of currently operated cell
*/ */
private ReadHolder currentReadHolder; private ReadHolder currentReadHolder;
/**
* Event processor
*/
private AnalysisEventProcessor analysisEventProcessor;
public AnalysisContextImpl(ReadWorkbook readWorkbook) { public AnalysisContextImpl(ReadWorkbook readWorkbook, ExcelTypeEnum actualExcelType) {
if (readWorkbook == null) { if (readWorkbook == null) {
throw new IllegalArgumentException("Workbook argument cannot be 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; currentReadHolder = readWorkbookHolder;
analysisEventProcessor = new DefaultAnalysisEventProcessor();
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Initialization 'AnalysisContextImpl' complete"); LOGGER.debug("Initialization 'AnalysisContextImpl' complete");
} }
@ -51,7 +72,16 @@ public class AnalysisContextImpl implements AnalysisContext {
@Override @Override
public void currentSheet(ReadSheet readSheet) { 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; currentReadHolder = readSheetHolder;
if (readWorkbookHolder.getHasReadSheet().contains(readSheetHolder.getSheetNo())) { if (readWorkbookHolder.getHasReadSheet().contains(readSheetHolder.getSheetNo())) {
throw new ExcelAnalysisException("Cannot read sheet repeatedly."); throw new ExcelAnalysisException("Cannot read sheet repeatedly.");
@ -92,6 +122,21 @@ public class AnalysisContextImpl implements AnalysisContext {
return readWorkbookHolder.getCustomObject(); return readWorkbookHolder.getCustomObject();
} }
@Override
public AnalysisEventProcessor analysisEventProcessor() {
return analysisEventProcessor;
}
@Override
public List<ReadSheet> readSheetList() {
return null;
}
@Override
public void readSheetList(List<ReadSheet> readSheetList) {
}
@Override @Override
public Sheet getCurrentSheet() { public Sheet getCurrentSheet() {
Sheet sheet = new Sheet(readSheetHolder.getSheetNo() + 1); Sheet sheet = new Sheet(readSheetHolder.getSheetNo() + 1);

79
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.CellData;
import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.DateUtils;
import com.alibaba.excel.util.FileUtils; import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.util.NumberDataFormatterUtils;
import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.util.StringUtils;
import com.alibaba.excel.util.WorkBookUtil; import com.alibaba.excel.util.WorkBookUtil;
import com.alibaba.excel.util.WriteHandlerUtils; import com.alibaba.excel.util.WriteHandlerUtils;
@ -106,34 +108,39 @@ public class WriteContextImpl implements WriteContext {
if (writeSheet == null) { if (writeSheet == null) {
throw new IllegalArgumentException("Sheet argument cannot be null"); throw new IllegalArgumentException("Sheet argument cannot be null");
} }
if (writeSheet.getSheetNo() == null || writeSheet.getSheetNo() <= 0) { if (selectSheetFromCache(writeSheet)) {
if (LOGGER.isDebugEnabled()) { return;
LOGGER.debug("Sheet number is null");
} }
writeSheet.setSheetNo(0); initCurrentSheetHolder(writeSheet);
// Initialization current sheet
initSheet(writeType);
}
private boolean selectSheetFromCache(WriteSheet writeSheet) {
writeSheetHolder = null;
if (writeSheet.getSheetNo() != null) {
writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheetIndexMap().get(writeSheet.getSheetNo());
}
if (writeSheetHolder == null && !StringUtils.isEmpty(writeSheet.getSheetName())) {
writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheetNameMap().get(writeSheet.getSheetName());
}
if (writeSheetHolder == null) {
return false;
} }
if (writeWorkbookHolder.getHasBeenInitializedSheet().containsKey(writeSheet.getSheetNo())) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Sheet:{} is already existed", writeSheet.getSheetNo()); LOGGER.debug("Sheet:{} is already existed", writeSheet.getSheetNo());
} }
writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheet().get(writeSheet.getSheetNo());
writeSheetHolder.setNewInitialization(Boolean.FALSE); writeSheetHolder.setNewInitialization(Boolean.FALSE);
writeTableHolder = null; writeTableHolder = null;
currentWriteHolder = writeSheetHolder; currentWriteHolder = writeSheetHolder;
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("CurrentConfiguration is writeSheetHolder"); LOGGER.debug("CurrentConfiguration is writeSheetHolder");
} }
return; return true;
}
initCurrentSheetHolder(writeSheet);
WriteHandlerUtils.beforeSheetCreate(this);
// Initialization current sheet
initSheet(writeType);
} }
private void initCurrentSheetHolder(WriteSheet writeSheet) { private void initCurrentSheetHolder(WriteSheet writeSheet) {
writeSheetHolder = new WriteSheetHolder(writeSheet, writeWorkbookHolder); writeSheetHolder = new WriteSheetHolder(writeSheet, writeWorkbookHolder);
writeWorkbookHolder.getHasBeenInitializedSheet().put(writeSheet.getSheetNo(), writeSheetHolder);
writeTableHolder = null; writeTableHolder = null;
currentWriteHolder = writeSheetHolder; currentWriteHolder = writeSheetHolder;
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
@ -142,17 +149,24 @@ public class WriteContextImpl implements WriteContext {
} }
private void initSheet(WriteTypeEnum writeType) { private void initSheet(WriteTypeEnum writeType) {
WriteHandlerUtils.beforeSheetCreate(this);
Sheet currentSheet; Sheet currentSheet;
try { try {
if (writeSheetHolder.getSheetNo() != null) {
currentSheet = writeWorkbookHolder.getWorkbook().getSheetAt(writeSheetHolder.getSheetNo()); currentSheet = writeWorkbookHolder.getWorkbook().getSheetAt(writeSheetHolder.getSheetNo());
writeSheetHolder writeSheetHolder
.setCachedSheet(writeWorkbookHolder.getCachedWorkbook().getSheetAt(writeSheetHolder.getSheetNo())); .setCachedSheet(writeWorkbookHolder.getCachedWorkbook().getSheetAt(writeSheetHolder.getSheetNo()));
} else {
// sheet name must not null
currentSheet = writeWorkbookHolder.getWorkbook().getSheet(writeSheetHolder.getSheetName());
writeSheetHolder
.setCachedSheet(writeWorkbookHolder.getCachedWorkbook().getSheet(writeSheetHolder.getSheetName()));
}
} catch (Exception e) { } catch (Exception e) {
if (LOGGER.isDebugEnabled()) { currentSheet = createSheet();
LOGGER.debug("Can not find sheet:{} ,now create it", writeSheetHolder.getSheetNo());
} }
currentSheet = WorkBookUtil.createSheet(writeWorkbookHolder.getWorkbook(), writeSheetHolder.getSheetName()); if (currentSheet == null) {
writeSheetHolder.setCachedSheet(currentSheet); currentSheet = createSheet();
} }
writeSheetHolder.setSheet(currentSheet); writeSheetHolder.setSheet(currentSheet);
WriteHandlerUtils.afterSheetCreate(this); WriteHandlerUtils.afterSheetCreate(this);
@ -160,6 +174,21 @@ public class WriteContextImpl implements WriteContext {
// Initialization head // Initialization head
initHead(writeSheetHolder.excelWriteHeadProperty()); initHead(writeSheetHolder.excelWriteHeadProperty());
} }
writeWorkbookHolder.getHasBeenInitializedSheetIndexMap().put(writeSheetHolder.getSheetNo(), writeSheetHolder);
writeWorkbookHolder.getHasBeenInitializedSheetNameMap().put(writeSheetHolder.getSheetName(), writeSheetHolder);
}
private Sheet createSheet() {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Can not find sheet:{} ,now create it", writeSheetHolder.getSheetNo());
}
if (StringUtils.isEmpty(writeSheetHolder.getSheetName())) {
writeSheetHolder.setSheetName(writeSheetHolder.getSheetNo().toString());
}
Sheet currentSheet =
WorkBookUtil.createSheet(writeWorkbookHolder.getWorkbook(), writeSheetHolder.getSheetName());
writeSheetHolder.setCachedSheet(currentSheet);
return currentSheet;
} }
public void initHead(ExcelWriteHeadProperty excelWriteHeadProperty) { public void initHead(ExcelWriteHeadProperty excelWriteHeadProperty) {
@ -280,7 +309,6 @@ public class WriteContextImpl implements WriteContext {
throwable = t; throwable = t;
} }
} }
if (!isOutputStreamEncrypt) { if (!isOutputStreamEncrypt) {
try { try {
if (writeExcel) { if (writeExcel) {
@ -291,7 +319,6 @@ public class WriteContextImpl implements WriteContext {
throwable = t; throwable = t;
} }
} }
try { try {
Workbook workbook = writeWorkbookHolder.getWorkbook(); Workbook workbook = writeWorkbookHolder.getWorkbook();
if (workbook instanceof SXSSFWorkbook) { if (workbook instanceof SXSSFWorkbook) {
@ -300,7 +327,6 @@ public class WriteContextImpl implements WriteContext {
} catch (Throwable t) { } catch (Throwable t) {
throwable = t; throwable = t;
} }
try { try {
if (writeWorkbookHolder.getAutoCloseStream() && writeWorkbookHolder.getOutputStream() != null) { if (writeWorkbookHolder.getAutoCloseStream() && writeWorkbookHolder.getOutputStream() != null) {
writeWorkbookHolder.getOutputStream().close(); writeWorkbookHolder.getOutputStream().close();
@ -308,7 +334,6 @@ public class WriteContextImpl implements WriteContext {
} catch (Throwable t) { } catch (Throwable t) {
throwable = t; throwable = t;
} }
if (writeExcel && !isOutputStreamEncrypt) { if (writeExcel && !isOutputStreamEncrypt) {
try { try {
doFileEncrypt07(); doFileEncrypt07();
@ -316,7 +341,6 @@ public class WriteContextImpl implements WriteContext {
throwable = t; throwable = t;
} }
} }
try { try {
if (writeWorkbookHolder.getTempTemplateInputStream() != null) { if (writeWorkbookHolder.getTempTemplateInputStream() != null) {
writeWorkbookHolder.getTempTemplateInputStream().close(); writeWorkbookHolder.getTempTemplateInputStream().close();
@ -324,18 +348,21 @@ public class WriteContextImpl implements WriteContext {
} catch (Throwable t) { } catch (Throwable t) {
throwable = t; throwable = t;
} }
clearEncrypt03(); clearEncrypt03();
removeThreadLocalCache();
if (throwable != null) { if (throwable != null) {
throw new ExcelGenerateException("Can not close IO.", throwable); throw new ExcelGenerateException("Can not close IO.", throwable);
} }
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Finished write."); LOGGER.debug("Finished write.");
} }
} }
private void removeThreadLocalCache() {
NumberDataFormatterUtils.removeThreadLocalCache();
DateUtils.removeThreadLocalCache();
}
@Override @Override
public Sheet getCurrentSheet() { public Sheet getCurrentSheet() {
return writeSheetHolder.getSheet(); return writeSheetHolder.getSheet();
@ -442,8 +469,10 @@ public class WriteContextImpl implements WriteContext {
OutputStream outputStream = encryptor.getDataStream(fileSystem); OutputStream outputStream = encryptor.getDataStream(fileSystem);
opcPackage.save(outputStream); opcPackage.save(outputStream);
} finally { } finally {
if (opcPackage != null) {
opcPackage.close(); opcPackage.close();
} }
}
return fileSystem; return fileSystem;
} }
} }

30
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();
}
}

26
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();
}

30
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();
}
}

26
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();
}

101
src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java

@ -48,56 +48,12 @@ public class DefaultConverterLoader {
private static Map<String, Converter> defaultWriteConverter; private static Map<String, Converter> defaultWriteConverter;
private static Map<String, Converter> allConverter; private static Map<String, Converter> allConverter;
/** static {
* Load default write converter initDefaultWriteConverter();
* initAllConverter();
* @return
*/
public static Map<String, Converter> loadDefaultWriteConverter() {
if (defaultWriteConverter != null) {
return defaultWriteConverter;
}
defaultWriteConverter = new HashMap<String, Converter>(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;
}
private static void putWriteConverter(Converter converter) {
defaultWriteConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter);
} }
/** private static void initAllConverter() {
* Load default read converter
*
* @return
*/
public static Map<String, Converter> loadDefaultReadConverter() {
return loadAllConverter();
}
/**
* Load all converter
*
* @return
*/
public static Map<String, Converter> loadAllConverter() {
if (allConverter != null) {
return allConverter;
}
allConverter = new HashMap<String, Converter>(64); allConverter = new HashMap<String, Converter>(64);
putAllConverter(new BigDecimalBooleanConverter()); putAllConverter(new BigDecimalBooleanConverter());
putAllConverter(new BigDecimalNumberConverter()); putAllConverter(new BigDecimalNumberConverter());
@ -138,6 +94,55 @@ public class DefaultConverterLoader {
putAllConverter(new StringNumberConverter()); putAllConverter(new StringNumberConverter());
putAllConverter(new StringStringConverter()); putAllConverter(new StringStringConverter());
putAllConverter(new StringErrorConverter()); putAllConverter(new StringErrorConverter());
}
private static void initDefaultWriteConverter() {
defaultWriteConverter = new HashMap<String, Converter>(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<String, Converter> loadDefaultWriteConverter() {
return defaultWriteConverter;
}
private static void putWriteConverter(Converter converter) {
defaultWriteConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter);
}
/**
* Load default read converter
*
* @return
*/
public static Map<String, Converter> loadDefaultReadConverter() {
return loadAllConverter();
}
/**
* Load all converter
*
* @return
*/
public static Map<String, Converter> loadAllConverter() {
return allConverter; return allConverter;
} }

2
src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java

@ -34,7 +34,7 @@ public class ByteNumberConverter implements Converter<Byte> {
@Override @Override
public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty, public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return new CellData(BigDecimal.valueOf(value)); return new CellData(new BigDecimal(Byte.toString(value)));
} }
} }

2
src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java

@ -34,7 +34,7 @@ public class FloatNumberConverter implements Converter<Float> {
@Override @Override
public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty, public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return new CellData(BigDecimal.valueOf(value)); return new CellData(new BigDecimal(Float.toString(value)));
} }
} }

2
src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java

@ -34,7 +34,7 @@ public class IntegerNumberConverter implements Converter<Integer> {
@Override @Override
public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return new CellData(BigDecimal.valueOf(value)); return new CellData(new BigDecimal(Integer.toString(value)));
} }
} }

2
src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java

@ -34,7 +34,7 @@ public class ShortNumberConverter implements Converter<Short> {
@Override @Override
public CellData convertToExcelData(Short value, ExcelContentProperty contentProperty, public CellData convertToExcelData(Short value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) { GlobalConfiguration globalConfiguration) {
return new CellData(BigDecimal.valueOf(value)); return new CellData(new BigDecimal(Short.toString(value)));
} }
} }

12
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.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.DateUtils; import com.alibaba.excel.util.DateUtils;
import com.alibaba.excel.util.NumberDataFormatterUtils;
import com.alibaba.excel.util.NumberUtils; import com.alibaba.excel.util.NumberUtils;
import com.alibaba.excel.util.StringUtils;
/** /**
* String and number converter * String and number converter
@ -44,13 +46,9 @@ public class StringNumberConverter implements Converter<String> {
return NumberUtils.format(cellData.getNumberValue(), contentProperty); return NumberUtils.format(cellData.getNumberValue(), contentProperty);
} }
// Excel defines formatting // Excel defines formatting
if (cellData.getDataFormat() != null) { if (cellData.getDataFormat() != null && !StringUtils.isEmpty(cellData.getDataFormatString())) {
if (DateUtil.isADateFormat(cellData.getDataFormat(), cellData.getDataFormatString())) { return NumberDataFormatterUtils.format(cellData.getNumberValue().doubleValue(), cellData.getDataFormat(),
return DateUtils.format(DateUtil.getJavaDate(cellData.getNumberValue().doubleValue(), cellData.getDataFormatString(), globalConfiguration);
globalConfiguration.getUse1904windowing(), null));
} else {
return NumberUtils.format(cellData.getNumberValue(), contentProperty);
}
} }
// Default conversion number // Default conversion number
return NumberUtils.format(cellData.getNumberValue(), contentProperty); return NumberUtils.format(cellData.getNumberValue(), contentProperty);

21
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,;
}

17
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,;
}

12
src/main/java/com/alibaba/excel/event/AbstractIgnoreExceptionReadListener.java

@ -1,6 +1,7 @@
package com.alibaba.excel.event; package com.alibaba.excel.event;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.read.listener.ReadListener;
/** /**
@ -20,6 +21,17 @@ public abstract class AbstractIgnoreExceptionReadListener<T> implements ReadList
@Override @Override
public void onException(Exception exception, AnalysisContext context) {} 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 @Override
public boolean hasNext(AnalysisContext context) { public boolean hasNext(AnalysisContext context) {
return true; return true;

12
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.context.AnalysisContext;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ConverterUtils; import com.alibaba.excel.util.ConverterUtils;
@ -27,6 +28,17 @@ public abstract class AnalysisEventListener<T> implements ReadListener<T> {
*/ */
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {} public void invokeHeadMap(Map<Integer, String> 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 * All listeners receive this method when any one Listener does an error report. If an exception is thrown here, the
* entire read will terminate. * entire read will terminate.

33
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;
}
}

12
src/main/java/com/alibaba/excel/metadata/AbstractHolder.java

@ -1,6 +1,7 @@
package com.alibaba.excel.metadata; package com.alibaba.excel.metadata;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import com.alibaba.excel.converters.Converter; import com.alibaba.excel.converters.Converter;
@ -27,7 +28,6 @@ public abstract class AbstractHolder implements ConfigurationHolder {
* Some global variables * Some global variables
*/ */
private GlobalConfiguration globalConfiguration; private GlobalConfiguration globalConfiguration;
/** /**
* <p> * <p>
* Read key: * Read key:
@ -58,6 +58,16 @@ public abstract class AbstractHolder implements ConfigurationHolder {
} else { } else {
globalConfiguration.setAutoTrim(basicParameter.getAutoTrim()); 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() { public Boolean getNewInitialization() {

98
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<T extends AbstractParameterBuilder, C extends BasicParameter> {
/**
* You can only choose one of the {@link #head(List)} and {@link #head(Class)}
*
* @param head
* @return
*/
public T head(List<List<String>> 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<Converter>());
}
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 <code>Locale</code> 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();
}

13
src/main/java/com/alibaba/excel/metadata/BasicParameter.java

@ -1,6 +1,7 @@
package com.alibaba.excel.metadata; package com.alibaba.excel.metadata;
import java.util.List; import java.util.List;
import java.util.Locale;
import com.alibaba.excel.converters.Converter; import com.alibaba.excel.converters.Converter;
@ -34,6 +35,11 @@ public class BasicParameter {
* @return * @return
*/ */
private Boolean use1904windowing; private Boolean use1904windowing;
/**
* A <code>Locale</code> object represents a specific geographical, political, or cultural region. This parameter is
* used when formatting dates and numbers.
*/
private Locale locale;
public List<List<String>> getHead() { public List<List<String>> getHead() {
return head; return head;
@ -75,4 +81,11 @@ public class BasicParameter {
this.use1904windowing = use1904windowing; this.use1904windowing = use1904windowing;
} }
public Locale getLocale() {
return locale;
}
public void setLocale(Locale locale) {
this.locale = locale;
}
} }

22
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();
}

38
src/main/java/com/alibaba/excel/metadata/CellData.java

@ -12,7 +12,7 @@ import com.alibaba.excel.util.StringUtils;
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
public class CellData<T> { public class CellData<T> extends AbstractCell {
private CellDataTypeEnum type; private CellDataTypeEnum type;
/** /**
* {@link CellDataTypeEnum#NUMBER} * {@link CellDataTypeEnum#NUMBER}
@ -226,6 +226,42 @@ public class CellData<T> {
} }
} }
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 @Override
public String toString() { public String toString() {
if (type == null) { if (type == null) {

121
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;
}
}

786
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.
* <p>
* 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<String,Format> formats
*/
private final Map<String, Format> formats = new HashMap<String, Format>();
/** 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<Integer> ms = new ArrayList<Integer>();
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 <tt>String</tt> based on the cell's <code>DataFormat</code>.
* i.e. "Thursday, January 02, 2003" , "01/02/2003" , "02-Jan" , etc.
* <p>
* 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 <tt>String</tt> based on the cell's <code>DataFormat</code>.
* Supported formats include currency, percents, decimals, phone number, SSN, etc.: "61.54%", "$100.00", "(800)
* 555-1234".
* <p>
* 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);
}
/**
* <p>
* Sets a default number format to be used when the Excel format cannot be parsed successfully. <b>Note:</b> This is
* a fall back for when an error occurs while parsing an Excel number format pattern. This will not affect cells
* with the <em>General</em> format.
* </p>
* <p>
* The value that will be passed to the Format's format method (specified by <code>java.text.Format#format</code>)
* will be a double value from a numeric cell. Therefore the code in the format method should expect a
* <code>Number</code> value.
* </p>
*
* @param format
* A Format instance to be used as a default
* @see Format#format
*/
public void setDefaultNumberFormat(Format format) {
for (Map.Entry<String, Format> entry : formats.entrySet()) {
if (entry.getValue() == defaultNumFormat) {
entry.setValue(format);
}
}
defaultNumFormat = format;
}
/**
* Adds a new format to the available formats.
* <p>
* The value that will be passed to the Format's format method (specified by <code>java.text.Format#format</code>)
* will be a double value from a numeric cell. Therefore the code in the format method should expect a
* <code>Number</code> value.
* </p>
*
* @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 <tt>DecimalFormat</tt> with parseIntegerOnly set <code>true</code>
*/
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);
}
}
}

15
src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java

@ -1,5 +1,7 @@
package com.alibaba.excel.metadata; package com.alibaba.excel.metadata;
import java.util.Locale;
/** /**
* Global configuration * Global configuration
* *
@ -18,6 +20,11 @@ public class GlobalConfiguration {
* @return * @return
*/ */
private Boolean use1904windowing; private Boolean use1904windowing;
/**
* A <code>Locale</code> object represents a specific geographical, political, or cultural region. This parameter is
* used when formatting dates and numbers.
*/
private Locale locale;
public Boolean getUse1904windowing() { public Boolean getUse1904windowing() {
return use1904windowing; return use1904windowing;
@ -34,4 +41,12 @@ public class GlobalConfiguration {
public void setAutoTrim(Boolean autoTrim) { public void setAutoTrim(Boolean autoTrim) {
this.autoTrim = autoTrim; this.autoTrim = autoTrim;
} }
public Locale getLocale() {
return locale;
}
public void setLocale(Locale locale) {
this.locale = locale;
}
} }

63
src/main/java/com/alibaba/excel/metadata/Head.java

@ -4,6 +4,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.alibaba.excel.metadata.property.ColumnWidthProperty; 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 * excel head
@ -35,6 +38,26 @@ public class Head {
* column with * column with
*/ */
private ColumnWidthProperty columnWidthProperty; 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<String> headNameList, Boolean forceIndex, public Head(Integer columnIndex, String fieldName, List<String> headNameList, Boolean forceIndex,
Boolean forceName) { Boolean forceName) {
@ -95,4 +118,44 @@ public class Head {
public void setForceName(Boolean forceName) { public void setForceName(Boolean forceName) {
this.forceName = 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;
}
} }

12
src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java

@ -1,7 +1,6 @@
package com.alibaba.excel.metadata.property; package com.alibaba.excel.metadata.property;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -12,8 +11,6 @@ import java.util.TreeMap;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat; import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.format.NumberFormat; 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.converters.Converter;
import com.alibaba.excel.enums.HeadKindEnum; import com.alibaba.excel.enums.HeadKindEnum;
import com.alibaba.excel.exception.ExcelCommonException; import com.alibaba.excel.exception.ExcelCommonException;
import com.alibaba.excel.exception.ExcelGenerateException;
import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.Holder; import com.alibaba.excel.metadata.Holder;
import com.alibaba.excel.util.ClassUtils; import com.alibaba.excel.util.ClassUtils;
@ -86,10 +82,10 @@ public class ExcelHeadProperty {
headIndex++; headIndex++;
} }
headKind = HeadKindEnum.STRING; headKind = HeadKindEnum.STRING;
} else { }
// convert headClazz to head // convert headClazz to head
initColumnProperties(holder, convertAllFiled); initColumnProperties(holder, convertAllFiled);
}
initHeadRowNumber(); initHeadRowNumber();
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("The initialization sheet/table 'ExcelHeadProperty' is complete , head kind is {}", headKind); LOGGER.debug("The initialization sheet/table 'ExcelHeadProperty' is complete , head kind is {}", headKind);
@ -163,11 +159,15 @@ public class ExcelHeadProperty {
List<String> tmpHeadList = new ArrayList<String>(); List<String> tmpHeadList = new ArrayList<String>();
boolean notForceName = excelProperty == null || excelProperty.value().length <= 0 boolean notForceName = excelProperty == null || excelProperty.value().length <= 0
|| (excelProperty.value().length == 1 && StringUtils.isEmpty((excelProperty.value())[0])); || (excelProperty.value().length == 1 && StringUtils.isEmpty((excelProperty.value())[0]));
if (headMap.containsKey(index)) {
tmpHeadList.addAll(headMap.get(index).getHeadNameList());
} else {
if (notForceName) { if (notForceName) {
tmpHeadList.add(field.getName()); tmpHeadList.add(field.getName());
} else { } else {
Collections.addAll(tmpHeadList, excelProperty.value()); Collections.addAll(tmpHeadList, excelProperty.value());
} }
}
Head head = new Head(index, field.getName(), tmpHeadList, forceIndex, !notForceName); Head head = new Head(index, field.getName(), tmpHeadList, forceIndex, !notForceName);
ExcelContentProperty excelContentProperty = new ExcelContentProperty(); ExcelContentProperty excelContentProperty = new ExcelContentProperty();
if (excelProperty != null) { if (excelProperty != null) {

180
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;
}
}

47
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;
}
}

74
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;
}
}

377
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 <code>true</code> 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 <i>Note: Ensure Foreground color is set prior to background color.</i>
*
* @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;
}
}

47
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<T extends AbstractExcelReaderParameterBuilder,
C extends ReadBasicParameter> extends AbstractParameterBuilder<T, C> {
/**
* Count the number of added heads when read sheet.
*
* <p>
* 0 - This Sheet has no head ,since the first row are the data
* <p>
* 1 - This Sheet has one row head , this is the default
* <p>
* 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<ReadListener>());
}
parameter().getCustomReadListenerList().add(readListener);
return self();
}
}

141
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.File;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.HashSet;
import java.util.List; import java.util.List;
import javax.xml.parsers.SAXParserFactory; import javax.xml.parsers.SAXParserFactory;
@ -11,9 +11,10 @@ import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.cache.ReadCache; import com.alibaba.excel.cache.ReadCache;
import com.alibaba.excel.cache.selector.ReadCacheSelector; import com.alibaba.excel.cache.selector.ReadCacheSelector;
import com.alibaba.excel.context.AnalysisContext; 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.AnalysisEventListener;
import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.event.SyncReadListener;
import com.alibaba.excel.read.listener.ModelBuildEventListener;
import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.read.metadata.ReadWorkbook;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
@ -22,7 +23,7 @@ import com.alibaba.excel.support.ExcelTypeEnum;
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
public class ExcelReaderBuilder { public class ExcelReaderBuilder extends AbstractExcelReaderParameterBuilder<ExcelReaderBuilder, ReadWorkbook> {
/** /**
* Workbook * Workbook
*/ */
@ -133,134 +134,83 @@ public class ExcelReaderBuilder {
} }
/** /**
* Count the number of added heads when read sheet. * Whether the encryption
*
* <p>
* 0 - This Sheet has no head ,since the first row are the data
* <p>
* 1 - This Sheet has one row head , this is the default
* <p>
* 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<List<String>> head) {
readWorkbook.setHead(head);
return this;
}
/**
* You can only choose one of the {@link ExcelReaderBuilder#head(List)} and {@link ExcelReaderBuilder#head(Class)}
* *
* @param clazz * @param password
* @return * @return
*/ */
public ExcelReaderBuilder head(Class clazz) { public ExcelReaderBuilder password(String password) {
readWorkbook.setClazz(clazz); readWorkbook.setPassword(password);
return this; return this;
} }
/** /**
* Custom type conversions override the default. * SAXParserFactory used when reading xlsx.
* <p>
* The default will automatically find.
* <p>
* Please pass in the name of a class ,like : "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"
* *
* @param converter * @see SAXParserFactory#newInstance()
* @see SAXParserFactory#newInstance(String, ClassLoader)
* @param xlsxSAXParserFactoryName
* @return * @return
*/ */
public ExcelReaderBuilder registerConverter(Converter converter) { public ExcelReaderBuilder xlsxSAXParserFactoryName(String xlsxSAXParserFactoryName) {
if (readWorkbook.getCustomConverterList() == null) { readWorkbook.setXlsxSAXParserFactoryName(xlsxSAXParserFactoryName);
readWorkbook.setCustomConverterList(new ArrayList<Converter>());
}
readWorkbook.getCustomConverterList().add(converter);
return this; return this;
} }
/** /**
* Custom type listener run after default * Read some extra information, not by default
* *
* @param readListener * @param extraType
* extra information type
* @return * @return
*/ */
public ExcelReaderBuilder registerReadListener(ReadListener readListener) { public ExcelReaderBuilder extraRead(CellExtraTypeEnum extraType) {
if (readWorkbook.getCustomReadListenerList() == null) { if (readWorkbook.getExtraReadSet() == null) {
readWorkbook.setCustomReadListenerList(new ArrayList<ReadListener>()); readWorkbook.setExtraReadSet(new HashSet<CellExtraTypeEnum>());
} }
readWorkbook.getCustomReadListenerList().add(readListener); readWorkbook.getExtraReadSet().add(extraType);
return this; return this;
} }
/** /**
* true if date uses 1904 windowing, or false if using 1900 date windowing. * Whether to use the default listener, which is used by default.
* * <p>
* default is false * The {@link ModelBuildEventListener} is loaded by default to convert the object.
* *
* @param use1904windowing * @param useDefaultListener
* @return * @return
*/ */
public ExcelReaderBuilder use1904windowing(Boolean use1904windowing) { public ExcelReaderBuilder useDefaultListener(Boolean useDefaultListener) {
readWorkbook.setUse1904windowing(use1904windowing); readWorkbook.setUseDefaultListener(useDefaultListener);
return this; return this;
} }
/** public ExcelReader build() {
* Automatic trim includes sheet name and content return new ExcelReader(readWorkbook);
*
* @param autoTrim
* @return
*/
public ExcelReaderBuilder autoTrim(Boolean autoTrim) {
readWorkbook.setAutoTrim(autoTrim);
return this;
} }
/** public void doReadAll() {
* Whether the encryption ExcelReader excelReader = build();
* excelReader.readAll();
* @param password excelReader.finish();
* @return
*/
public ExcelReaderBuilder password(String password) {
readWorkbook.setPassword(password);
return this;
} }
/** /**
* SAXParserFactory used when reading xlsx. * Synchronous reads return results
* <p>
* The default will automatically find.
* <p>
* 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)
* @param xlsxSAXParserFactoryName
* @return * @return
*/ */
public ExcelReaderBuilder xlsxSAXParserFactoryName(String xlsxSAXParserFactoryName) { public <T> List<T> doReadAllSync() {
readWorkbook.setXlsxSAXParserFactoryName(xlsxSAXParserFactoryName); SyncReadListener syncReadListener = new SyncReadListener();
return this; registerReadListener(syncReadListener);
}
public ExcelReader build() {
return new ExcelReader(readWorkbook);
}
public ExcelReader doReadAll() {
ExcelReader excelReader = build(); ExcelReader excelReader = build();
excelReader.readAll(); excelReader.readAll();
excelReader.finish(); excelReader.finish();
return excelReader; return (List<T>)syncReadListener.getList();
} }
public ExcelReaderSheetBuilder sheet() { public ExcelReaderSheetBuilder sheet() {
@ -285,4 +235,9 @@ public class ExcelReaderBuilder {
} }
return excelReaderSheetBuilder; return excelReaderSheetBuilder;
} }
@Override
protected ReadWorkbook parameter() {
return readWorkbook;
}
} }

101
src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java

@ -1,14 +1,11 @@
package com.alibaba.excel.read.builder; package com.alibaba.excel.read.builder;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.alibaba.excel.ExcelReader; import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.event.SyncReadListener; import com.alibaba.excel.event.SyncReadListener;
import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.exception.ExcelGenerateException;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.read.metadata.ReadSheet;
/** /**
@ -16,7 +13,7 @@ import com.alibaba.excel.read.metadata.ReadSheet;
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
public class ExcelReaderSheetBuilder { public class ExcelReaderSheetBuilder extends AbstractExcelReaderParameterBuilder<ExcelReaderSheetBuilder, ReadSheet> {
private ExcelReader excelReader; private ExcelReader excelReader;
/** /**
* Sheet * Sheet
@ -54,98 +51,6 @@ public class ExcelReaderSheetBuilder {
return this; return this;
} }
/**
* Count the number of added heads when read sheet.
*
* <p>
* 0 - This Sheet has no head ,since the first row are the data
* <p>
* 1 - This Sheet has one row head , this is the default
* <p>
* 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<List<String>> 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<Converter>());
}
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<ReadListener>());
}
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() { public ReadSheet build() {
return readSheet; return readSheet;
} }
@ -177,4 +82,8 @@ public class ExcelReaderSheetBuilder {
return (List<T>)syncReadListener.getList(); return (List<T>)syncReadListener.getList();
} }
@Override
protected ReadSheet parameter() {
return readSheet;
}
} }

10
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(), (String)ConverterUtils.convertToJavaObject(cellData, null, null, currentReadHolder.converterMap(),
currentReadHolder.globalConfiguration(), context.readRowHolder().getRowIndex(), key)); currentReadHolder.globalConfiguration(), context.readRowHolder().getRowIndex(), key));
} }
int headSize = currentReadHolder.excelReadHeadProperty().getHeadMap().size();
while (index < headSize) {
map.put(index, null);
index++;
}
return map; return map;
} else { } else {
// Compatible with the old code the old code returns a list // 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(), (String)ConverterUtils.convertToJavaObject(cellData, null, null, currentReadHolder.converterMap(),
currentReadHolder.globalConfiguration(), context.readRowHolder().getRowIndex(), key)); currentReadHolder.globalConfiguration(), context.readRowHolder().getRowIndex(), key));
} }
int headSize = currentReadHolder.excelReadHeadProperty().getHeadMap().size();
while (index < headSize) {
list.add(null);
index++;
}
return list; return list;
} }
} }

11
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.context.AnalysisContext;
import com.alibaba.excel.event.Listener; import com.alibaba.excel.event.Listener;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.CellExtra;
/** /**
* Interface to listen for read results * Interface to listen for read results
@ -40,6 +41,16 @@ public interface ReadListener<T> extends Listener {
*/ */
void invoke(T data, AnalysisContext context); 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 * if have something to do after all analysis
* *

39
src/main/java/com/alibaba/excel/read/listener/ReadListenerRegistryCenter.java

@ -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);
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save