Browse Source

add SheetDataSaxHandler

Looly 5 years ago
parent
commit
7d4838a0a4

+ 1 - 0
CHANGELOG.md

@@ -15,6 +15,7 @@
 * 【dfa    】     增加FoundWord(pr#1290@Github)
 * 【dfa    】     增加FoundWord(pr#1290@Github)
 * 【core   】     增加Segment(pr#1290@Github)
 * 【core   】     增加Segment(pr#1290@Github)
 * 【core   】     增加CharSequenceUtil
 * 【core   】     增加CharSequenceUtil
+* 【poi    】     Excel07SaxReader拆分出SheetDataSaxHandler
 
 
 ### Bug修复
 ### Bug修复
 * 【cache  】     修复Cache中get重复misCount计数问题(issue#1281@Github)
 * 【cache  】     修复Cache中get重复misCount计数问题(issue#1281@Github)

+ 16 - 289
hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel07SaxReader.java

@@ -2,30 +2,19 @@ package cn.hutool.poi.excel.sax;
 
 
 import cn.hutool.core.io.IORuntimeException;
 import cn.hutool.core.io.IORuntimeException;
 import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.text.StrBuilder;
 import cn.hutool.core.util.NumberUtil;
 import cn.hutool.core.util.NumberUtil;
-import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
-import cn.hutool.poi.excel.cell.FormulaCellValue;
 import cn.hutool.poi.excel.sax.handler.RowHandler;
 import cn.hutool.poi.excel.sax.handler.RowHandler;
 import cn.hutool.poi.exceptions.POIException;
 import cn.hutool.poi.exceptions.POIException;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
 import org.apache.poi.openxml4j.opc.OPCPackage;
 import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.ss.usermodel.BuiltinFormats;
 import org.apache.poi.xssf.eventusermodel.XSSFReader;
 import org.apache.poi.xssf.eventusermodel.XSSFReader;
-import org.apache.poi.xssf.model.SharedStringsTable;
-import org.apache.poi.xssf.model.StylesTable;
-import org.apache.poi.xssf.usermodel.XSSFCellStyle;
-import org.xml.sax.Attributes;
-import org.xml.sax.helpers.DefaultHandler;
 
 
 import java.io.File;
 import java.io.File;
 import java.io.IOException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStream;
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.Iterator;
-import java.util.List;
 
 
 /**
 /**
  * Sax方式读取Excel文件<br>
  * Sax方式读取Excel文件<br>
@@ -34,52 +23,11 @@ import java.util.List;
  * @author Looly
  * @author Looly
  * @since 3.1.2
  * @since 3.1.2
  */
  */
-public class Excel07SaxReader extends DefaultHandler implements ExcelSaxReader<Excel07SaxReader> {
+public class Excel07SaxReader implements ExcelSaxReader<Excel07SaxReader> {
 
 
 	// sheet r:Id前缀
 	// sheet r:Id前缀
 	private static final String RID_PREFIX = "rId";
 	private static final String RID_PREFIX = "rId";
-
-	// 单元格的格式表,对应style.xml
-	private StylesTable stylesTable;
-	// excel 2007 的共享字符串表,对应sharedString.xml
-	private SharedStringsTable sharedStringsTable;
-	// sheet的索引
-	private int sheetIndex;
-
-	// 当前非空行
-	private int index;
-	// 当前列
-	private int curCell;
-	// 单元数据类型
-	private CellDataType cellDataType;
-	// 当前行号,从0开始
-	private long rowNumber;
-	// 当前列坐标, 如A1,B5
-	private String curCoordinate;
-	// 当前节点名称
-	private ElementName curElementName;
-	// 前一个列的坐标
-	private String preCoordinate;
-	// 行的最大列坐标
-	private String maxCellCoordinate;
-	// 单元格样式
-	private XSSFCellStyle xssfCellStyle;
-	// 单元格存储的格式化字符串,nmtFmt的formatCode属性的值
-	private String numFmtString;
-	// 是否处于sheetData标签内,sax只解析此标签内的内容,其它标签忽略
-	private boolean isInSheetData;
-
-	// 上一次的内容
-	private final StrBuilder lastContent = StrUtil.strBuilder();
-	// 上一次的内容
-	private final StrBuilder lastFormula = StrUtil.strBuilder();
-	// 存储每行的列元素
-	private List<Object> rowCellList = new ArrayList<>();
-
-	/**
-	 * 行处理器
-	 */
-	private RowHandler rowHandler;
+	private final SheetDataSaxHandler handler;
 
 
 	/**
 	/**
 	 * 构造
 	 * 构造
@@ -87,7 +35,7 @@ public class Excel07SaxReader extends DefaultHandler implements ExcelSaxReader<E
 	 * @param rowHandler 行处理器
 	 * @param rowHandler 行处理器
 	 */
 	 */
 	public Excel07SaxReader(RowHandler rowHandler) {
 	public Excel07SaxReader(RowHandler rowHandler) {
-		this.rowHandler = rowHandler;
+		this.handler = new SheetDataSaxHandler(rowHandler);
 	}
 	}
 
 
 	/**
 	/**
@@ -97,7 +45,7 @@ public class Excel07SaxReader extends DefaultHandler implements ExcelSaxReader<E
 	 * @return this
 	 * @return this
 	 */
 	 */
 	public Excel07SaxReader setRowHandler(RowHandler rowHandler) {
 	public Excel07SaxReader setRowHandler(RowHandler rowHandler) {
-		this.rowHandler = rowHandler;
+		this.handler.setRowHandler(rowHandler);
 		return this;
 		return this;
 	}
 	}
 
 
@@ -174,14 +122,14 @@ public class Excel07SaxReader extends DefaultHandler implements ExcelSaxReader<E
 	public Excel07SaxReader read(XSSFReader xssfReader, String idOrRid) throws POIException {
 	public Excel07SaxReader read(XSSFReader xssfReader, String idOrRid) throws POIException {
 		// 获取共享样式表
 		// 获取共享样式表
 		try {
 		try {
-			stylesTable = xssfReader.getStylesTable();
+			this.handler.stylesTable = xssfReader.getStylesTable();
 		} catch (Exception e) {
 		} catch (Exception e) {
 			//ignore
 			//ignore
 		}
 		}
 
 
 		// 获取共享字符串表
 		// 获取共享字符串表
 		try {
 		try {
-			this.sharedStringsTable = xssfReader.getSharedStringsTable();
+			this.handler.sharedStringsTable = xssfReader.getSharedStringsTable();
 		} catch (IOException e) {
 		} catch (IOException e) {
 			throw new IORuntimeException(e);
 			throw new IORuntimeException(e);
 		} catch (InvalidFormatException e) {
 		} catch (InvalidFormatException e) {
@@ -192,89 +140,6 @@ public class Excel07SaxReader extends DefaultHandler implements ExcelSaxReader<E
 	}
 	}
 	// ------------------------------------------------------------------------------ Read end
 	// ------------------------------------------------------------------------------ Read end
 
 
-	/**
-	 * 读到一个xml开始标签时的回调处理方法
-	 */
-	@Override
-	public void startElement(String uri, String localName, String qName, Attributes attributes) {
-		if("sheetData".equals(qName)){
-			this.isInSheetData = true;
-			return;
-		}
-
-		if(false == this.isInSheetData){
-			// 非sheetData标签,忽略解析
-			return;
-		}
-
-		final ElementName name = ElementName.of(qName);
-		this.curElementName = name;
-
-		if(null != name){
-			switch (name){
-				case row:
-					// 行开始
-					startRow(attributes);
-					break;
-				case c:
-					// 单元格元素
-					startCell(attributes);
-					break;
-			}
-		}
-	}
-
-	/**
-	 * 标签结束的回调处理方法
-	 */
-	@Override
-	public void endElement(String uri, String localName, String qName) {
-		if("sheetData".equals(qName)){
-			// sheetData结束,不再解析别的标签
-			this.isInSheetData = false;
-			return;
-		}
-
-		if(false == this.isInSheetData){
-			// 非sheetData标签,忽略解析
-			return;
-		}
-
-		this.curElementName = null;
-		if (ElementName.c.match(qName)) { // 单元格结束
-			endCell();
-		} else if (ElementName.row.match(qName)) {// 行结束
-			endRow();
-		}
-		// 其它标签忽略
-	}
-
-	/**
-	 * s标签结束的回调处理方法
-	 */
-	@Override
-	public void characters(char[] ch, int start, int length) {
-		if(false == this.isInSheetData){
-			// 非sheetData标签,忽略解析
-			return;
-		}
-
-		final ElementName elementName = this.curElementName;
-		if(null != elementName){
-			switch (elementName){
-				case v:
-					// 得到单元格内容的值
-					lastContent.append(ch, start, length);
-					break;
-				case f:
-					// 得到单元格内容的值
-					lastFormula.append(ch, start, length);
-					break;
-			}
-		}
-		// 其它标签忽略
-	}
-
 	// --------------------------------------------------------------------------------------- Private method start
 	// --------------------------------------------------------------------------------------- Private method start
 
 
 	/**
 	/**
@@ -295,25 +160,25 @@ public class Excel07SaxReader extends DefaultHandler implements ExcelSaxReader<E
 				idOrRid = rid;
 				idOrRid = rid;
 			}
 			}
 		}
 		}
-		this.sheetIndex = Integer.parseInt(StrUtil.removePrefixIgnoreCase(idOrRid, RID_PREFIX));
+		this.handler.sheetIndex = Integer.parseInt(StrUtil.removePrefixIgnoreCase(idOrRid, RID_PREFIX));
 		InputStream sheetInputStream = null;
 		InputStream sheetInputStream = null;
 		try {
 		try {
-			if (this.sheetIndex > -1) {
+			if (this.handler.sheetIndex > -1) {
 				// 根据 rId# 或 rSheet# 查找sheet
 				// 根据 rId# 或 rSheet# 查找sheet
-				sheetInputStream = xssfReader.getSheet(RID_PREFIX + (this.sheetIndex + 1));
-				ExcelSaxUtil.readFrom(sheetInputStream, this);
-				rowHandler.doAfterAllAnalysed();
+				sheetInputStream = xssfReader.getSheet(RID_PREFIX + (this.handler.sheetIndex + 1));
+				ExcelSaxUtil.readFrom(sheetInputStream, this.handler);
+				this.handler.rowHandler.doAfterAllAnalysed();
 			} else {
 			} else {
-				this.sheetIndex = -1;
+				this.handler.sheetIndex = -1;
 				// 遍历所有sheet
 				// 遍历所有sheet
 				final Iterator<InputStream> sheetInputStreams = xssfReader.getSheetsData();
 				final Iterator<InputStream> sheetInputStreams = xssfReader.getSheetsData();
 				while (sheetInputStreams.hasNext()) {
 				while (sheetInputStreams.hasNext()) {
 					// 重新读取一个sheet时行归零
 					// 重新读取一个sheet时行归零
-					index = 0;
-					this.sheetIndex++;
+					this.handler.index = 0;
+					this.handler.sheetIndex++;
 					sheetInputStream = sheetInputStreams.next();
 					sheetInputStream = sheetInputStreams.next();
-					ExcelSaxUtil.readFrom(sheetInputStream, this);
-					rowHandler.doAfterAllAnalysed();
+					ExcelSaxUtil.readFrom(sheetInputStream, this.handler);
+					this.handler.rowHandler.doAfterAllAnalysed();
 				}
 				}
 			}
 			}
 		} catch (RuntimeException e) {
 		} catch (RuntimeException e) {
@@ -325,143 +190,5 @@ public class Excel07SaxReader extends DefaultHandler implements ExcelSaxReader<E
 		}
 		}
 		return this;
 		return this;
 	}
 	}
-
-	/**
-	 * 行开始
-	 *
-	 * @param attributes 属性列表
-	 */
-	private void startRow(Attributes attributes) {
-		final String rValue = AttributeName.r.getValue(attributes);
-		if(null != rValue){
-			this.rowNumber = Long.parseLong(rValue) - 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();
-		lastFormula.reset();
-	}
-
-	/**
-	 * 一个单元格结尾
-	 */
-	private void endCell() {
-		// 补全单元格之间的空格
-		fillBlankCell(preCoordinate, curCoordinate, false);
-
-		final String contentStr = StrUtil.trim(lastContent);
-		Object value = ExcelSaxUtil.getDataValue(this.cellDataType, contentStr, this.sharedStringsTable, this.numFmtString);
-		if(false == this.lastFormula.isEmpty()){
-			value = new FormulaCellValue(StrUtil.trim(lastFormula), value);
-		}
-		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>
-	 *
-	 * @param preCoordinate 前一个单元格坐标
-	 * @param curCoordinate 当前单元格坐标
-	 * @param isEnd         是否为最后一个单元格
-	 */
-	private void fillBlankCell(String preCoordinate, String curCoordinate, boolean isEnd) {
-		if (false == curCoordinate.equals(preCoordinate)) {
-			int len = ExcelSaxUtil.countNullCell(preCoordinate, curCoordinate);
-			if (isEnd) {
-				len++;
-			}
-			while (len-- > 0) {
-				addCellValue(curCell++, StrUtil.EMPTY);
-			}
-		}
-	}
-
-	/**
-	 * 设置单元格的类型
-	 *
-	 * @param attributes 属性
-	 */
-	private void setCellType(Attributes attributes) {
-		// numFmtString的值
-		numFmtString = StrUtil.EMPTY;
-		this.cellDataType = CellDataType.of(AttributeName.t.getValue(attributes));
-
-		// 获取单元格的xf索引,对应style.xml中cellXfs的子元素xf
-		if (null != this.stylesTable) {
-			final String xfIndexStr = AttributeName.s.getValue(attributes);
-			if (null != xfIndexStr) {
-				this.xssfCellStyle = stylesTable.getStyleAt(Integer.parseInt(xfIndexStr));
-				// 单元格存储格式的索引,对应style.xml中的numFmts元素的子元素索引
-				final int numFmtIndex = xssfCellStyle.getDataFormat();
-				this.numFmtString = ObjectUtil.defaultIfNull(
-						xssfCellStyle.getDataFormatString(),
-						BuiltinFormats.getBuiltinFormat(numFmtIndex));
-				if (CellDataType.NUMBER == this.cellDataType && ExcelSaxUtil.isDateFormat(numFmtIndex, numFmtString)) {
-					cellDataType = CellDataType.DATE;
-				}
-			}
-		}
-
-	}
 	// --------------------------------------------------------------------------------------- Private method end
 	// --------------------------------------------------------------------------------------- Private method end
 }
 }

+ 307 - 0
hutool-poi/src/main/java/cn/hutool/poi/excel/sax/SheetDataSaxHandler.java

@@ -0,0 +1,307 @@
+package cn.hutool.poi.excel.sax;
+
+import cn.hutool.core.text.StrBuilder;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.poi.excel.cell.FormulaCellValue;
+import cn.hutool.poi.excel.sax.handler.RowHandler;
+import org.apache.poi.ss.usermodel.BuiltinFormats;
+import org.apache.poi.xssf.model.SharedStringsTable;
+import org.apache.poi.xssf.model.StylesTable;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * sheetData标签内容读取处理器
+ *
+ * <pre>
+ * &lt;sheetData&gt;&lt;/sheetData&gt;
+ * </pre>
+ * @since 5.5.3
+ */
+public class SheetDataSaxHandler extends DefaultHandler {
+
+	// 单元格的格式表,对应style.xml
+	protected StylesTable stylesTable;
+	// excel 2007 的共享字符串表,对应sharedString.xml
+	protected SharedStringsTable sharedStringsTable;
+	// sheet的索引
+	protected int sheetIndex;
+
+	// 当前非空行
+	protected int index;
+	// 当前列
+	private int curCell;
+	// 单元数据类型
+	private CellDataType cellDataType;
+	// 当前行号,从0开始
+	private long rowNumber;
+	// 当前列坐标, 如A1,B5
+	private String curCoordinate;
+	// 当前节点名称
+	private ElementName curElementName;
+	// 前一个列的坐标
+	private String preCoordinate;
+	// 行的最大列坐标
+	private String maxCellCoordinate;
+	// 单元格样式
+	private XSSFCellStyle xssfCellStyle;
+	// 单元格存储的格式化字符串,nmtFmt的formatCode属性的值
+	private String numFmtString;
+	// 是否处于sheetData标签内,sax只解析此标签内的内容,其它标签忽略
+	private boolean isInSheetData;
+
+	// 上一次的内容
+	private final StrBuilder lastContent = StrUtil.strBuilder();
+	// 上一次的内容
+	private final StrBuilder lastFormula = StrUtil.strBuilder();
+	// 存储每行的列元素
+	private List<Object> rowCellList = new ArrayList<>();
+
+	public SheetDataSaxHandler(RowHandler rowHandler){
+		this.rowHandler = rowHandler;
+	}
+
+	/**
+	 * 行处理器
+	 */
+	protected RowHandler rowHandler;
+
+	/**
+	 * 设置行处理器
+	 *
+	 * @param rowHandler 行处理器
+	 */
+	public void setRowHandler(RowHandler rowHandler) {
+		this.rowHandler = rowHandler;
+	}
+
+	/**
+	 * 读到一个xml开始标签时的回调处理方法
+	 */
+	@Override
+	public void startElement(String uri, String localName, String qName, Attributes attributes) {
+		if ("sheetData".equals(qName)) {
+			this.isInSheetData = true;
+			return;
+		}
+
+		if (false == this.isInSheetData) {
+			// 非sheetData标签,忽略解析
+			return;
+		}
+
+		final ElementName name = ElementName.of(qName);
+		this.curElementName = name;
+
+		if (null != name) {
+			switch (name) {
+				case row:
+					// 行开始
+					startRow(attributes);
+					break;
+				case c:
+					// 单元格元素
+					startCell(attributes);
+					break;
+			}
+		}
+	}
+
+	/**
+	 * 标签结束的回调处理方法
+	 */
+	@Override
+	public void endElement(String uri, String localName, String qName) {
+		if ("sheetData".equals(qName)) {
+			// sheetData结束,不再解析别的标签
+			this.isInSheetData = false;
+			return;
+		}
+
+		if (false == this.isInSheetData) {
+			// 非sheetData标签,忽略解析
+			return;
+		}
+
+		this.curElementName = null;
+		if (ElementName.c.match(qName)) { // 单元格结束
+			endCell();
+		} else if (ElementName.row.match(qName)) {// 行结束
+			endRow();
+		}
+		// 其它标签忽略
+	}
+
+	/**
+	 * s标签结束的回调处理方法
+	 */
+	@Override
+	public void characters(char[] ch, int start, int length) {
+		if (false == this.isInSheetData) {
+			// 非sheetData标签,忽略解析
+			return;
+		}
+
+		final ElementName elementName = this.curElementName;
+		if (null != elementName) {
+			switch (elementName) {
+				case v:
+					// 得到单元格内容的值
+					lastContent.append(ch, start, length);
+					break;
+				case f:
+					// 得到单元格内容的值
+					lastFormula.append(ch, start, length);
+					break;
+			}
+		}
+		// 其它标签忽略
+	}
+
+	// --------------------------------------------------------------------------------------- Private method start
+
+	/**
+	 * 行开始
+	 *
+	 * @param attributes 属性列表
+	 */
+	private void startRow(Attributes attributes) {
+		final String rValue = AttributeName.r.getValue(attributes);
+		if (null != rValue) {
+			this.rowNumber = Long.parseLong(rValue) - 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();
+		lastFormula.reset();
+	}
+
+	/**
+	 * 一行结尾
+	 */
+	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;
+	}
+
+	/**
+	 * 一个单元格结尾
+	 */
+	private void endCell() {
+		// 补全单元格之间的空格
+		fillBlankCell(preCoordinate, curCoordinate, false);
+
+		final String contentStr = StrUtil.trim(lastContent);
+		Object value = ExcelSaxUtil.getDataValue(this.cellDataType, contentStr, this.sharedStringsTable, this.numFmtString);
+		if (false == this.lastFormula.isEmpty()) {
+			value = new FormulaCellValue(StrUtil.trim(lastFormula), value);
+		}
+		addCellValue(curCell++, value);
+	}
+
+	/**
+	 * 在一行中的指定列增加值
+	 *
+	 * @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>
+	 *
+	 * @param preCoordinate 前一个单元格坐标
+	 * @param curCoordinate 当前单元格坐标
+	 * @param isEnd         是否为最后一个单元格
+	 */
+	private void fillBlankCell(String preCoordinate, String curCoordinate, boolean isEnd) {
+		if (false == curCoordinate.equals(preCoordinate)) {
+			int len = ExcelSaxUtil.countNullCell(preCoordinate, curCoordinate);
+			if (isEnd) {
+				len++;
+			}
+			while (len-- > 0) {
+				addCellValue(curCell++, StrUtil.EMPTY);
+			}
+		}
+	}
+
+	/**
+	 * 设置单元格的类型
+	 *
+	 * @param attributes 属性
+	 */
+	private void setCellType(Attributes attributes) {
+		// numFmtString的值
+		numFmtString = StrUtil.EMPTY;
+		this.cellDataType = CellDataType.of(AttributeName.t.getValue(attributes));
+
+		// 获取单元格的xf索引,对应style.xml中cellXfs的子元素xf
+		if (null != this.stylesTable) {
+			final String xfIndexStr = AttributeName.s.getValue(attributes);
+			if (null != xfIndexStr) {
+				this.xssfCellStyle = stylesTable.getStyleAt(Integer.parseInt(xfIndexStr));
+				// 单元格存储格式的索引,对应style.xml中的numFmts元素的子元素索引
+				final int numFmtIndex = xssfCellStyle.getDataFormat();
+				this.numFmtString = ObjectUtil.defaultIfNull(
+						xssfCellStyle.getDataFormatString(),
+						BuiltinFormats.getBuiltinFormat(numFmtIndex));
+				if (CellDataType.NUMBER == this.cellDataType && ExcelSaxUtil.isDateFormat(numFmtIndex, numFmtString)) {
+					cellDataType = CellDataType.DATE;
+				}
+			}
+		}
+
+	}
+
+	// --------------------------------------------------------------------------------------- Private method end
+}