|
|
@@ -1,6 +1,7 @@
|
|
|
package cn.hutool.poi.excel.sax;
|
|
|
|
|
|
import cn.hutool.core.io.IoUtil;
|
|
|
+import cn.hutool.core.text.StrBuilder;
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
import cn.hutool.poi.excel.sax.handler.RowHandler;
|
|
|
import cn.hutool.poi.exceptions.POIException;
|
|
|
@@ -29,52 +30,39 @@ import java.util.List;
|
|
|
*/
|
|
|
public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> implements ContentHandler {
|
|
|
|
|
|
- /**
|
|
|
- * Cell单元格元素
|
|
|
- */
|
|
|
- private static final String C_ELEMENT = "c";
|
|
|
- /**
|
|
|
- * 行元素
|
|
|
- */
|
|
|
- private static final String ROW_ELEMENT = "row";
|
|
|
- /**
|
|
|
- * Cell中的行列号(Reference),行模式下此为行号属性名,列模式下为列号属性名
|
|
|
- */
|
|
|
- private static final String R_ATTR = "r";
|
|
|
- /**
|
|
|
- * SST(SharedStringsTable) 的索引,样式index
|
|
|
- */
|
|
|
- private static final String S_ATTR_VALUE = "s";
|
|
|
- // 列中属性值
|
|
|
- private static final String T_ATTR_VALUE = "t";
|
|
|
// sheet r:Id前缀
|
|
|
private static final String RID_PREFIX = "rId";
|
|
|
|
|
|
+ // 单元格的格式表,对应style.xml
|
|
|
+ private StylesTable stylesTable;
|
|
|
// excel 2007 的共享字符串表,对应sharedString.xml
|
|
|
private SharedStringsTable sharedStringsTable;
|
|
|
- // 当前行
|
|
|
- private int curRow;
|
|
|
+ // sheet的索引
|
|
|
+ private int sheetIndex;
|
|
|
+
|
|
|
+ // 当前非空行
|
|
|
+ private int index;
|
|
|
// 当前列
|
|
|
private int curCell;
|
|
|
- // 上一次的内容
|
|
|
- private final StringBuilder lastContent = new StringBuilder(64);
|
|
|
// 单元数据类型
|
|
|
private CellDataType cellDataType;
|
|
|
+ // 当前行号,从0开始
|
|
|
+ private long rowNumber;
|
|
|
// 当前列坐标, 如A1,B5
|
|
|
private String curCoordinate;
|
|
|
// 前一个列的坐标
|
|
|
private String preCoordinate;
|
|
|
// 行的最大列坐标
|
|
|
private String maxCellCoordinate;
|
|
|
- // 单元格的格式表,对应style.xml
|
|
|
- private StylesTable stylesTable;
|
|
|
+ // 单元格样式
|
|
|
+ private XSSFCellStyle xssfCellStyle;
|
|
|
// 单元格存储的格式化字符串,nmtFmt的formatCode属性的值
|
|
|
private String numFmtString;
|
|
|
- // sheet的索引
|
|
|
- private int sheetIndex;
|
|
|
|
|
|
+ // 上一次的内容
|
|
|
+ private final StrBuilder lastContent = StrUtil.strBuilder();
|
|
|
// 存储每行的列元素
|
|
|
- List<Object> rowCellList = new ArrayList<>();
|
|
|
+ private List<Object> rowCellList = new ArrayList<>();
|
|
|
|
|
|
/**
|
|
|
* 行处理器
|
|
|
@@ -136,9 +124,9 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
|
|
|
final XSSFReader xssfReader = new XSSFReader(opcPackage);
|
|
|
|
|
|
// 获取共享样式表
|
|
|
- try{
|
|
|
+ try {
|
|
|
stylesTable = xssfReader.getStylesTable();
|
|
|
- } catch (Exception e){
|
|
|
+ } catch (Exception e) {
|
|
|
//ignore
|
|
|
}
|
|
|
// 获取共享字符串表
|
|
|
@@ -155,7 +143,7 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
|
|
|
final Iterator<InputStream> sheetInputStreams = xssfReader.getSheetsData();
|
|
|
while (sheetInputStreams.hasNext()) {
|
|
|
// 重新读取一个sheet时行归零
|
|
|
- curRow = 0;
|
|
|
+ index = 0;
|
|
|
this.sheetIndex++;
|
|
|
sheetInputStream = sheetInputStreams.next();
|
|
|
ExcelSaxUtil.readFrom(sheetInputStream, this);
|
|
|
@@ -178,24 +166,11 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
|
|
|
*/
|
|
|
@Override
|
|
|
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
|
|
- // 单元格元素
|
|
|
- if (C_ELEMENT.equals(localName)) {
|
|
|
- // 获取当前列坐标
|
|
|
- String tempCurCoordinate = attributes.getValue(R_ATTR);
|
|
|
- // 前一列为null,则将其设置为"@",A为第一列,ascii码为65,前一列即为@,ascii码64
|
|
|
- if (preCoordinate == null) {
|
|
|
- preCoordinate = String.valueOf(ExcelSaxUtil.CELL_FILL_CHAR);
|
|
|
- } else {
|
|
|
- // 存在,则前一列要设置为上一列的坐标
|
|
|
- preCoordinate = curCoordinate;
|
|
|
- }
|
|
|
- // 重置当前列
|
|
|
- curCoordinate = tempCurCoordinate;
|
|
|
- // 设置单元格类型
|
|
|
- setCellType(attributes);
|
|
|
+ if (ElementName.row.match(localName)) {// 行开始
|
|
|
+ startRow(attributes);
|
|
|
+ } else if (ElementName.c.match(localName)) {// 单元格元素
|
|
|
+ startCell(attributes);
|
|
|
}
|
|
|
-
|
|
|
- lastContent.setLength(0);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -203,42 +178,10 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
|
|
|
*/
|
|
|
@Override
|
|
|
public void endElement(String uri, String localName, String qName) {
|
|
|
- final String contentStr = StrUtil.trim(lastContent);
|
|
|
-
|
|
|
-// if (T_ELEMENT.equals(qName)) {
|
|
|
-// // type标签
|
|
|
-// // rowCellList.add(curCell++, contentStr);
|
|
|
-// } else
|
|
|
- if (C_ELEMENT.equals(localName)) {
|
|
|
- // cell标签
|
|
|
- Object value = ExcelSaxUtil.getDataValue(this.cellDataType, contentStr, this.sharedStringsTable, this.numFmtString);
|
|
|
- // 补全单元格之间的空格
|
|
|
- fillBlankCell(preCoordinate, curCoordinate, false);
|
|
|
- rowCellList.add(curCell++, value);
|
|
|
- } else if (ROW_ELEMENT.equals(localName)) {
|
|
|
- // 如果是row标签,说明已经到了一行的结尾
|
|
|
- // 最大列坐标以第一行的为准
|
|
|
- if (curRow == 0) {
|
|
|
- maxCellCoordinate = curCoordinate;
|
|
|
- }
|
|
|
-
|
|
|
- // 补全一行尾部可能缺失的单元格
|
|
|
- if (maxCellCoordinate != null) {
|
|
|
- fillBlankCell(curCoordinate, maxCellCoordinate, true);
|
|
|
- }
|
|
|
-
|
|
|
- rowHandler.handle(sheetIndex, curRow, rowCellList);
|
|
|
-
|
|
|
- // 一行结束
|
|
|
- // 新建一个新列,之前的列抛弃(可能被回收或rowHandler处理)
|
|
|
- rowCellList = new ArrayList<>(curCell + 1);
|
|
|
- // 行数增加
|
|
|
- curRow++;
|
|
|
- // 当前列置0
|
|
|
- curCell = 0;
|
|
|
- // 置空当前列坐标和前一列坐标
|
|
|
- curCoordinate = null;
|
|
|
- preCoordinate = null;
|
|
|
+ if (ElementName.c.match(localName)) { // 单元格结束
|
|
|
+ endCell();
|
|
|
+ } else if (ElementName.row.match(localName)) {// 行结束
|
|
|
+ endRow();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -297,6 +240,89 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
|
|
|
// --------------------------------------------------------------------------------------- Pass method end
|
|
|
|
|
|
// --------------------------------------------------------------------------------------- Private method start
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 行开始
|
|
|
+ *
|
|
|
+ * @param attributes 属性列表
|
|
|
+ */
|
|
|
+ private void startRow(Attributes attributes) {
|
|
|
+ this.rowNumber = Long.parseLong(AttributeName.r.getValue(attributes)) - 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 单元格开始
|
|
|
+ *
|
|
|
+ * @param attributes 属性列表
|
|
|
+ */
|
|
|
+ private void startCell(Attributes attributes) {
|
|
|
+ // 获取当前列坐标
|
|
|
+ final String tempCurCoordinate = AttributeName.r.getValue(attributes);
|
|
|
+ // 前一列为null,则将其设置为"@",A为第一列,ascii码为65,前一列即为@,ascii码64
|
|
|
+ if (preCoordinate == null) {
|
|
|
+ preCoordinate = String.valueOf(ExcelSaxUtil.CELL_FILL_CHAR);
|
|
|
+ } else {
|
|
|
+ // 存在,则前一列要设置为上一列的坐标
|
|
|
+ preCoordinate = curCoordinate;
|
|
|
+ }
|
|
|
+ // 重置当前列
|
|
|
+ curCoordinate = tempCurCoordinate;
|
|
|
+ // 设置单元格类型
|
|
|
+ setCellType(attributes);
|
|
|
+
|
|
|
+ // 清空之前的数据
|
|
|
+ lastContent.reset();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 一个单元格结尾
|
|
|
+ */
|
|
|
+ private void endCell() {
|
|
|
+ final String contentStr = StrUtil.trim(lastContent);
|
|
|
+ final Object value = ExcelSaxUtil.getDataValue(this.cellDataType, contentStr, this.sharedStringsTable, this.numFmtString);
|
|
|
+ // 补全单元格之间的空格
|
|
|
+ fillBlankCell(preCoordinate, curCoordinate, false);
|
|
|
+ addCellValue(curCell++, value);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 一行结尾
|
|
|
+ */
|
|
|
+ private void endRow() {
|
|
|
+ // 最大列坐标以第一个非空行的为准
|
|
|
+ if (index == 0) {
|
|
|
+ maxCellCoordinate = curCoordinate;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 补全一行尾部可能缺失的单元格
|
|
|
+ if (maxCellCoordinate != null) {
|
|
|
+ fillBlankCell(curCoordinate, maxCellCoordinate, true);
|
|
|
+ }
|
|
|
+
|
|
|
+ rowHandler.handle(sheetIndex, rowNumber, rowCellList);
|
|
|
+
|
|
|
+ // 一行结束
|
|
|
+ // 新建一个新列,之前的列抛弃(可能被回收或rowHandler处理)
|
|
|
+ rowCellList = new ArrayList<>(curCell + 1);
|
|
|
+ // 行数增加
|
|
|
+ index++;
|
|
|
+ // 当前列置0
|
|
|
+ curCell = 0;
|
|
|
+ // 置空当前列坐标和前一列坐标
|
|
|
+ curCoordinate = null;
|
|
|
+ preCoordinate = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 在一行中的指定列增加值
|
|
|
+ * @param index 位置
|
|
|
+ * @param value 值
|
|
|
+ */
|
|
|
+ private void addCellValue(int index, Object value){
|
|
|
+ this.rowCellList.add(index, value);
|
|
|
+ this.rowHandler.handleCell(this.sheetIndex, this.rowNumber, index, value, this.xssfCellStyle);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 填充空白单元格,如果前一个单元格大于后一个,不需要填充<br>
|
|
|
*
|
|
|
@@ -311,7 +337,7 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
|
|
|
len++;
|
|
|
}
|
|
|
while (len-- > 0) {
|
|
|
- rowCellList.add(curCell++, "");
|
|
|
+ addCellValue(curCell++, "");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -319,19 +345,19 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
|
|
|
/**
|
|
|
* 设置单元格的类型
|
|
|
*
|
|
|
- * @param attribute 属性
|
|
|
+ * @param attributes 属性
|
|
|
*/
|
|
|
- private void setCellType(Attributes attribute) {
|
|
|
+ private void setCellType(Attributes attributes) {
|
|
|
// numFmtString的值
|
|
|
numFmtString = "";
|
|
|
- this.cellDataType = CellDataType.of(attribute.getValue(T_ATTR_VALUE));
|
|
|
+ this.cellDataType = CellDataType.of(AttributeName.t.getValue(attributes));
|
|
|
|
|
|
// 获取单元格的xf索引,对应style.xml中cellXfs的子元素xf
|
|
|
- if(null != this.stylesTable){
|
|
|
- final String xfIndexStr = attribute.getValue(S_ATTR_VALUE);
|
|
|
+ if (null != this.stylesTable) {
|
|
|
+ final String xfIndexStr = AttributeName.s.getValue(attributes);
|
|
|
if (null != xfIndexStr) {
|
|
|
int xfIndex = Integer.parseInt(xfIndexStr);
|
|
|
- final XSSFCellStyle xssfCellStyle = stylesTable.getStyleAt(xfIndex);
|
|
|
+ this.xssfCellStyle = stylesTable.getStyleAt(xfIndex);
|
|
|
numFmtString = xssfCellStyle.getDataFormatString();
|
|
|
// 单元格存储格式的索引,对应style.xml中的numFmts元素的子元素索引
|
|
|
int numFmtIndex = xssfCellStyle.getDataFormat();
|