This is an automated email from the ASF dual-hosted git repository.
fanningpj pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/poi.git
The following commit(s) were added to refs/heads/trunk by this push:
new 63c0bf9368 New api for reading xlsb (#920)
63c0bf9368 is described below
commit 63c0bf9368474ba77c601feb181fd114823fc42b
Author: AdRiley <[email protected]>
AuthorDate: Tue Oct 21 14:19:16 2025 +0100
New api for reading xlsb (#920)
* Add new API
* Add testBasicXSSFBSheetContentsHandler
* Add testCommentsXSSFBSheetContentsHandler
* Add testDateXSSFBSheetContentsHandler
* Fix comment
* Code Review feedback
* Code review feedback
* Fix backwards compatibility
* rename helper method
* Organise imports
* Add @since POI 5.5.0
---
.../apache/poi/xssf/binary/XSSFBSheetHandler.java | 320 ++++++++++++++++++---
.../poi/xssf/eventusermodel/TestXSSFBReader.java | 252 +++++++++++++++-
2 files changed, 534 insertions(+), 38 deletions(-)
diff --git
a/poi-ooxml/src/main/java/org/apache/poi/xssf/binary/XSSFBSheetHandler.java
b/poi-ooxml/src/main/java/org/apache/poi/xssf/binary/XSSFBSheetHandler.java
index 7a24234046..24676ac7b9 100644
--- a/poi-ooxml/src/main/java/org/apache/poi/xssf/binary/XSSFBSheetHandler.java
+++ b/poi-ooxml/src/main/java/org/apache/poi/xssf/binary/XSSFBSheetHandler.java
@@ -23,6 +23,8 @@ import java.util.Queue;
import org.apache.poi.ss.usermodel.BuiltinFormats;
import org.apache.poi.ss.usermodel.DataFormatter;
+import org.apache.poi.ss.usermodel.ExcelNumberFormat;
+import org.apache.poi.ss.usermodel.FormulaError;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.util.CellAddress;
import org.apache.poi.util.Internal;
@@ -41,10 +43,9 @@ public class XSSFBSheetHandler extends XSSFBParser {
private static final int CHECK_ALL_ROWS = -1;
private final SharedStrings stringsTable;
- private final XSSFSheetXMLHandler.SheetContentsHandler handler;
+ private final XSSFBSheetContentsHandler handler;
private final XSSFBStylesTable styles;
private final XSSFBCommentsTable comments;
- private final DataFormatter dataFormatter;
private final boolean formulasNotResults;//TODO: implement this
private int lastEndedRow = -1;
@@ -55,6 +56,51 @@ public class XSSFBSheetHandler extends XSSFBParser {
private StringBuilder xlWideStringBuffer = new StringBuilder();
private final XSSFBCellHeader cellBuffer = new XSSFBCellHeader();
+
+ /**
+ * Creates a handler that forwards native POI cell types to the supplied
{@link
+ * XSSFBSheetContentsHandler}.
+ *
+ * <p>Select this overload when the consumer expects the raw cell
representation rather than
+ * formatted strings.
+ *
+ * @param is XLSB worksheet stream to parse
+ * @param styles table providing cell style and number format metadata
+ * @param comments optional comments table, may be {@code null}
+ * @param strings shared strings table used by the sheet
+ * @param sheetContentsHandler callback receiving native cell events
+ * @since POI 5.5.0
+ */
+ public XSSFBSheetHandler(InputStream is,
+ XSSFBStylesTable styles,
+ XSSFBCommentsTable comments,
+ SharedStrings strings,
+ XSSFBSheetContentsHandler sheetContentsHandler,
+ boolean formulasNotResults) {
+ super(is);
+ this.styles = styles;
+ this.comments = comments;
+ this.stringsTable = strings;
+ this.handler = sheetContentsHandler;
+ this.formulasNotResults = formulasNotResults;
+ }
+
+ /**
+ * Creates a handler that converts numeric and date cells to formatted
strings via {@link
+ * DataFormatter}.
+ *
+ * <p>Select this overload when the consumer expects formatted string
values rather than raw
+ * cell representations.
+ *
+ * @param is XLSB worksheet stream to parse
+ * @param styles table providing cell style and number format metadata
+ * @param comments optional comments table, may be {@code null}
+ * @param strings shared strings table used by the sheet
+ * @param sheetContentsHandler callback receiving formatted string values
+ * @param dataFormatter formatter applied to numeric and date cells
+ * @see #XSSFBSheetHandler(InputStream, XSSFBStylesTable,
XSSFBCommentsTable, SharedStrings,
+ * XSSFBSheetContentsHandler, boolean)
+ */
public XSSFBSheetHandler(InputStream is,
XSSFBStylesTable styles,
XSSFBCommentsTable comments,
@@ -66,11 +112,18 @@ public class XSSFBSheetHandler extends XSSFBParser {
this.styles = styles;
this.comments = comments;
this.stringsTable = strings;
- this.handler = sheetContentsHandler;
- this.dataFormatter = dataFormatter;
+ this.handler = new
XSSFBSheetContentsHandlerWrapper(sheetContentsHandler, dataFormatter);
this.formulasNotResults = formulasNotResults;
}
+ /**
+ * Dispatches a parsed XLSB record to the appropriate specialised handler.
+ *
+ * @param id numeric record identifier supplied by {@link XSSFBParser}
+ * @param data raw record payload
+ * @throws XSSFBParseException if the record cannot be processed according
to the XLSB spec
+ * @see XSSFBRecordType
+ */
@Override
public void handleRecord(int id, byte[] data) throws XSSFBParseException {
XSSFBRecordType type = XSSFBRecordType.lookup(id);
@@ -133,86 +186,117 @@ public class XSSFBSheetHandler extends XSSFBParser {
checkMissedComments(currentRow, cellBuffer.getColNum());
}
- private void handleCellValue(String formattedValue) {
- CellAddress cellAddress = new CellAddress(currentRow,
cellBuffer.getColNum());
+ private void handleStringCellValue(String val) {
+ CellAddress cellAddress = getCellAddress();
+ XSSFBComment comment = getCellComment(cellAddress);
+ handler.stringCell(cellAddress.formatAsString(), val, comment);
+ }
+
+ private void handleDoubleCellValue(double val) {
+ CellAddress cellAddress = getCellAddress();
+ XSSFBComment comment = getCellComment(cellAddress);
+ ExcelNumberFormat nf = getExcelNumberFormat();
+ handler.doubleCell(cellAddress.formatAsString(), val, comment, nf);
+ }
+
+ private void handleErrorCellValue(int val) {
+ FormulaError fe;
+ try {
+ fe = FormulaError.forInt(val);
+ } catch (IllegalArgumentException e) {
+ fe = null;
+ }
+ CellAddress cellAddress = getCellAddress();
+ XSSFBComment comment = getCellComment(cellAddress);
+ handler.errorCell(cellAddress.formatAsString(), fe, comment);
+ }
+
+ private CellAddress getCellAddress() {
+ return new CellAddress(currentRow, cellBuffer.getColNum());
+ }
+
+ private XSSFBComment getCellComment(CellAddress cellAddress) {
XSSFBComment comment = null;
if (comments != null) {
comment = comments.get(cellAddress);
}
- handler.cell(cellAddress.formatAsString(), formattedValue, comment);
+ return comment;
+ }
+
+ private ExcelNumberFormat getExcelNumberFormat() {
+ int styleIdx = cellBuffer.getStyleIdx();
+ String formatString = styles.getNumberFormatString(styleIdx);
+ short styleIndex = styles.getNumberFormatIndex(styleIdx);
+ // for now, if formatString is null, silently punt
+ // and use "General". Not the best behavior,
+ // but we're doing it now in the streaming and non-streaming
+ // extractors for xlsx. See BUG-61053
+ if (formatString == null) {
+ formatString = BuiltinFormats.getBuiltinFormat(0);
+ styleIndex = 0;
+ }
+ return new ExcelNumberFormat(styleIndex, formatString);
}
private void handleFmlaNum(byte[] data) {
beforeCellValue(data);
//xNum
double val = LittleEndian.getDouble(data, XSSFBCellHeader.length);
- handleCellValue(formatVal(val, cellBuffer.getStyleIdx()));
+ handleDoubleCellValue(val);
}
private void handleCellSt(byte[] data) {
beforeCellValue(data);
xlWideStringBuffer.setLength(0);
XSSFBUtils.readXLWideString(data, XSSFBCellHeader.length,
xlWideStringBuffer);
- handleCellValue(xlWideStringBuffer.toString());
+ handleStringCellValue(xlWideStringBuffer.toString());
}
private void handleFmlaString(byte[] data) {
beforeCellValue(data);
xlWideStringBuffer.setLength(0);
XSSFBUtils.readXLWideString(data, XSSFBCellHeader.length,
xlWideStringBuffer);
- handleCellValue(xlWideStringBuffer.toString());
+ handleStringCellValue(xlWideStringBuffer.toString());
}
private void handleCellError(byte[] data) {
beforeCellValue(data);
- //TODO, read byte to figure out the type of error
- handleCellValue("ERROR");
+ int val = data[XSSFBCellHeader.length] & 0xFF;
+ handleErrorCellValue(val);
}
private void handleFmlaError(byte[] data) {
beforeCellValue(data);
- //TODO, read byte to figure out the type of error
- handleCellValue("ERROR");
+ int val = data[XSSFBCellHeader.length] & 0xFF;
+ handleErrorCellValue(val);
}
private void handleBoolean(byte[] data) {
beforeCellValue(data);
- String formattedVal = (data[XSSFBCellHeader.length] == 1) ? "TRUE" :
"FALSE";
- handleCellValue(formattedVal);
+ boolean val = data[XSSFBCellHeader.length] == 1;
+ CellAddress cellAddress = getCellAddress();
+ XSSFBComment comment = getCellComment(cellAddress);
+ handler.booleanCell(cellAddress.formatAsString(), val, comment);
}
private void handleCellReal(byte[] data) {
beforeCellValue(data);
//xNum
double val = LittleEndian.getDouble(data, XSSFBCellHeader.length);
- handleCellValue(formatVal(val, cellBuffer.getStyleIdx()));
+ handleDoubleCellValue(val);
}
private void handleCellRk(byte[] data) {
beforeCellValue(data);
double val = rkNumber(data, XSSFBCellHeader.length);
- handleCellValue(formatVal(val, cellBuffer.getStyleIdx()));
- }
-
- private String formatVal(double val, int styleIdx) {
- String formatString = styles.getNumberFormatString(styleIdx);
- short styleIndex = styles.getNumberFormatIndex(styleIdx);
- //for now, if formatString is null, silently punt
- //and use "General". Not the best behavior,
- //but we're doing it now in the streaming and non-streaming
- //extractors for xlsx. See BUG-61053
- if (formatString == null) {
- formatString = BuiltinFormats.getBuiltinFormat(0);
- styleIndex = 0;
- }
- return dataFormatter.formatRawCellContents(val, styleIndex,
formatString);
+ handleDoubleCellValue(val);
}
private void handleBrtCellIsst(byte[] data) {
beforeCellValue(data);
int idx = XSSFBUtils.castToInt(LittleEndian.getUInt(data,
XSSFBCellHeader.length));
RichTextString rtss = stringsTable.getItemAt(idx);
- handleCellValue(rtss.getString());
+ handleStringCellValue(rtss.getString());
}
@@ -300,7 +384,7 @@ public class XSSFBSheetHandler extends XSSFBParser {
}
private void dumpEmptyCellComment(CellAddress cellAddress, XSSFBComment
comment) {
- handler.cell(cellAddress.formatAsString(), null, comment);
+ handler.stringCell(cellAddress.formatAsString(), null, comment);
}
private double rkNumber(byte[] data, int offset) {
@@ -326,6 +410,174 @@ public class XSSFBSheetHandler extends XSSFBParser {
return d;
}
+ /**
+ * Receives streaming callbacks while {@link XSSFBSheetHandler} parses an
XLSB sheet.
+ *
+ * @see XSSFBSheetHandler
+ * @since POI 5.5.0
+ */
+ public interface XSSFBSheetContentsHandler {
+ /**
+ * Signals that a row has started before any of its cells are
delivered.
+ *
+ * @param rowNum zero-based row index
+ * @see #endRow(int)
+ */
+ void startRow(int rowNum);
+
+ /**
+ * Signals that a row has ended after all of its cells and comments
were processed.
+ *
+ * @param rowNum zero-based row index
+ * @see #startRow(int)
+ */
+ void endRow(int rowNum);
+
+ /**
+ * Handles a cell that resolves to a string value, possibly
representing a comment-only cell.
+ *
+ * @param cellReference A1-style cell address
+ * @param value string contents, or {@code null} if only a comment is
present
+ * @param comment associated comment, or {@code null} if absent
+ * <p>Sheets that have missing or empty cells may result in sparse
calls to <code>cell
+ * </code>. See the code in <code>
+ *
poi-examples/src/main/java/org/apache/poi/xssf/eventusermodel/XLSX2CSV.java</code>
for an
+ * example of how to handle this scenario.
+ * @see #doubleCell(String, double, XSSFComment, ExcelNumberFormat)
+ */
+ void stringCell(String cellReference, String value, XSSFComment
comment);
+
+ /**
+ * Handles a numeric cell while providing the corresponding {@link
ExcelNumberFormat}.
+ *
+ * @param cellReference A1-style cell address
+ * @param value numeric value extracted from the sheet
+ * @param comment associated comment, or {@code null} if absent
+ * @param nf number format describing how the value should be rendered
+ * <p>Sheets that have missing or empty cells may result in sparse
calls to <code>cell
+ * </code>. See the code in <code>
+ *
poi-examples/src/main/java/org/apache/poi/xssf/eventusermodel/XLSX2CSV.java</code>
for an
+ * example of how to handle this scenario.
+ * @see #stringCell(String, String, XSSFComment)
+ */
+ void doubleCell(String cellReference, double value, XSSFComment
comment, ExcelNumberFormat nf);
+
+ /**
+ * Handles a boolean cell.
+ *
+ * @param cellReference A1-style cell address
+ * @param value boolean value stored in the cell
+ * @param comment associated comment, or {@code null} if absent
+ * <p>Sheets that have missing or empty cells may result in sparse
calls to <code>cell
+ * </code>. See the code in <code>
+ *
poi-examples/src/main/java/org/apache/poi/xssf/eventusermodel/XLSX2CSV.java</code>
for an
+ * example of how to handle this scenario.
+ * @see #stringCell(String, String, XSSFComment)
+ */
+ void booleanCell(String cellReference, boolean value, XSSFComment
comment);
+
+ /**
+ * Handles a cell that evaluates to an error.
+ *
+ * @param cellReference A1-style cell address
+ * @param fe mapped {@link FormulaError}, or {@code null} when the
error code is unknown
+ * @param comment associated comment, or {@code null} if absent
+ * <p>Sheets that have missing or empty cells may result in sparse
calls to <code>cell
+ * </code>. See the code in <code>
+ *
poi-examples/src/main/java/org/apache/poi/xssf/eventusermodel/XLSX2CSV.java</code>
for an
+ * example of how to handle this scenario.
+ * @see FormulaError
+ */
+ void errorCell(String cellReference, FormulaError fe, XSSFComment
comment);
+
+ /**
+ * Receives header or footer text encountered in the sheet.
+ *
+ * @param text resolved header or footer text
+ * @param isHeader {@code true} when the text belongs to a header,
otherwise {@code false}
+ * @param tagName POI-internal tag representing the header or footer
section
+ * @see #endSheet()
+ */
+ void headerFooter(String text, boolean isHeader, String tagName);
+
+ /**
+ * Signals that the sheet has been completely processed.
+ *
+ * @see #startRow(int)
+ */
+ void endSheet();
+ }
+
+ /**
+ * Bridges a {@link XSSFSheetXMLHandler.SheetContentsHandler} to the {@link
+ * XSSFBSheetContentsHandler} contract.
+ *
+ * @see XSSFSheetXMLHandler
+ */
+ private final class XSSFBSheetContentsHandlerWrapper implements
XSSFBSheetContentsHandler {
+ private final XSSFSheetXMLHandler.SheetContentsHandler delegate;
+ private final DataFormatter dataFormatter;
+
+ /**
+ * Creates a wrapper that forwards events to the XML sheet handler
while formatting numeric
+ * cells.
+ *
+ * @param delegate target handler compatible with the XML streaming API
+ * @param dataFormatter formatter used for numeric and date cell
rendering
+ */
+ XSSFBSheetContentsHandlerWrapper(
+ XSSFSheetXMLHandler.SheetContentsHandler delegate, DataFormatter
dataFormatter) {
+ this.delegate = delegate;
+ this.dataFormatter = dataFormatter;
+ }
+
+ @Override
+ public void startRow(int rowNum) {
+ delegate.startRow(rowNum);
+ }
+
+ @Override
+ public void endRow(int rowNum) {
+ delegate.endRow(rowNum);
+ }
+
+ @Override
+ public void stringCell(String cellReference, String value, XSSFComment
comment) {
+ delegate.cell(cellReference, value, comment);
+ }
+
+ @Override
+ public void doubleCell(
+ String cellReference, double value, XSSFComment comment,
ExcelNumberFormat nf) {
+ String formattedValue =
+ dataFormatter.formatRawCellContents(value, nf.getIdx(),
nf.getFormat());
+ delegate.cell(cellReference, formattedValue, comment);
+ }
+
+ @Override
+ public void booleanCell(String cellReference, boolean value,
XSSFComment comment) {
+ delegate.cell(cellReference, Boolean.toString(value), comment);
+ }
+
+ @Override
+ public void errorCell(String cellReference, FormulaError fe,
XSSFComment comment) {
+ // For backward compatibility, we pass "ERROR" as the cell value.
+ // If you need the actual error code, you should implement
+ // XSSFBSheetContentsHandler directly
+ delegate.cell(cellReference, "ERROR", comment);
+ }
+
+ @Override
+ public void headerFooter(String text, boolean isHeader, String
tagName) {
+ delegate.headerFooter(text, isHeader, tagName);
+ }
+
+ @Override
+ public void endSheet() {
+ delegate.endSheet();
+ }
+ }
+
/**
* You need to implement this to handle the results
* of the sheet parsing.
diff --git
a/poi-ooxml/src/test/java/org/apache/poi/xssf/eventusermodel/TestXSSFBReader.java
b/poi-ooxml/src/test/java/org/apache/poi/xssf/eventusermodel/TestXSSFBReader.java
index 3fa96264f0..9ea4652f3e 100644
---
a/poi-ooxml/src/test/java/org/apache/poi/xssf/eventusermodel/TestXSSFBReader.java
+++
b/poi-ooxml/src/test/java/org/apache/poi/xssf/eventusermodel/TestXSSFBReader.java
@@ -17,10 +17,6 @@
package org.apache.poi.xssf.eventusermodel;
-import static org.apache.poi.POITestCase.assertContains;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
@@ -28,11 +24,29 @@ import java.util.List;
import org.apache.poi.POIDataSamples;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.ss.usermodel.DataFormatter;
+import org.apache.poi.ss.usermodel.ExcelNumberFormat;
+import org.apache.poi.ss.usermodel.FormulaError;
import org.apache.poi.xssf.binary.XSSFBSharedStringsTable;
import org.apache.poi.xssf.binary.XSSFBSheetHandler;
import org.apache.poi.xssf.binary.XSSFBStylesTable;
import org.apache.poi.xssf.usermodel.XSSFComment;
import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
+import org.mockito.InOrder;
+import org.mockito.quality.Strictness;
+
+import static org.apache.poi.POITestCase.assertContains;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.withSettings;
class TestXSSFBReader {
@@ -216,4 +230,234 @@ class TestXSSFBReader {
return sb.toString();
}
}
+
+ private static XSSFBSheetHandler.XSSFBSheetContentsHandler
mockSheetContentsHandler() {
+ return mock(
+ XSSFBSheetHandler.XSSFBSheetContentsHandler.class,
+ withSettings().strictness(Strictness.STRICT_STUBS));
+ }
+
+ private static ArgumentMatcher<XSSFComment> commentWith(String author,
String text) {
+ return comment -> comment != null
+ && author.equals(comment.getAuthor())
+ && comment.getString() != null
+ && text.equals(comment.getString().toString().trim());
+ }
+
+ private void readAllSheetsFromWorkbook(String fileName,
+ XSSFBSheetHandler.XSSFBSheetContentsHandler handler) throws
Exception {
+ try (OPCPackage pkg =
OPCPackage.open(_ssTests.openResourceAsStream(fileName))) {
+ XSSFBReader r = new XSSFBReader(pkg);
+ assertNotNull(r.getXSSFBStylesTable());
+ XSSFBSharedStringsTable sst = new XSSFBSharedStringsTable(pkg);
+ XSSFBStylesTable xssfbStylesTable = r.getXSSFBStylesTable();
+ XSSFBReader.SheetIterator it = (XSSFBReader.SheetIterator)
r.getSheetsData();
+
+ while (it.hasNext()) {
+ InputStream is = it.next();
+ XSSFBSheetHandler sheetHandler = new XSSFBSheetHandler(is,
+ xssfbStylesTable,
+ it.getXSSFBSheetComments(),
+ sst,
+ handler,
+ false);
+ sheetHandler.parse();
+ }
+ }
+ }
+
+ @Test
+ void testBasicXSSFBSheetContentsHandler() throws Exception {
+ XSSFBSheetHandler.XSSFBSheetContentsHandler handler =
mockSheetContentsHandler();
+ readAllSheetsFromWorkbook("testVarious.xlsb", handler);
+
+ InOrder ordered = inOrder(handler);
+ ordered.verify(handler).startRow(0);
+ ordered.verify(handler).stringCell(eq("A1"), eq("String"), isNull());
+ ordered.verify(handler).stringCell(eq("B1"), eq("This is a string"),
isNull());
+ ordered.verify(handler).endRow(0);
+
+ ordered.verify(handler).startRow(1);
+ ordered.verify(handler).stringCell(eq("A2"), eq("integer"), isNull());
+ ordered.verify(handler).doubleCell(eq("B2"), eq(13.0d), isNull(),
any(ExcelNumberFormat.class));
+ ordered.verify(handler).endRow(1);
+
+ ordered.verify(handler).startRow(2);
+ ordered.verify(handler).stringCell(eq("A3"), eq("float"), isNull());
+ ordered.verify(handler).doubleCell(eq("B3"), eq(13.1211231321d),
isNull(), any(ExcelNumberFormat.class));
+ ordered.verify(handler).endRow(2);
+
+ ordered.verify(handler).startRow(3);
+ ordered.verify(handler).stringCell(eq("A4"), eq("currency"), isNull());
+ ordered.verify(handler).doubleCell(eq("B4"), eq(3.03d), isNull(),
any(ExcelNumberFormat.class));
+ ordered.verify(handler).endRow(3);
+
+ ordered.verify(handler).startRow(4);
+ ordered.verify(handler).stringCell(eq("A5"), eq("percent"), isNull());
+ ordered.verify(handler).doubleCell(eq("B5"), eq(0.2d), isNull(),
any(ExcelNumberFormat.class));
+ ordered.verify(handler).endRow(4);
+
+ ordered.verify(handler).startRow(5);
+ ordered.verify(handler).stringCell(eq("A6"), eq("float 2"), isNull());
+ ordered.verify(handler).doubleCell(eq("B6"), eq(13.12131231d),
isNull(), any(ExcelNumberFormat.class));
+ ordered.verify(handler).endRow(5);
+
+ ordered.verify(handler).startRow(6);
+ ordered.verify(handler).stringCell(eq("A7"), eq("long int"), isNull());
+ ordered.verify(handler).doubleCell(eq("B7"), eq(1.23456789012345E14d),
isNull(), any(ExcelNumberFormat.class));
+ ordered.verify(handler).endRow(6);
+
+ ordered.verify(handler).startRow(7);
+ ordered.verify(handler).stringCell(eq("A8"), eq("longer int"),
isNull());
+ ordered.verify(handler).doubleCell(eq("B8"), eq(1.23456789012345E15d),
isNull(), any(ExcelNumberFormat.class));
+ ordered.verify(handler).stringCell(eq("C8"), isNull(),
notNull(XSSFComment.class));
+ ordered.verify(handler).endRow(7);
+
+ ordered.verify(handler).startRow(8);
+ ordered.verify(handler).stringCell(eq("A9"), eq("fraction"), isNull());
+ ordered.verify(handler).doubleCell(eq("B9"), eq(0.25d), isNull(),
any(ExcelNumberFormat.class));
+ ordered.verify(handler).endRow(8);
+
+ ordered.verify(handler).startRow(9);
+ ordered.verify(handler).stringCell(eq("A10"), eq("date"), isNull());
+ ordered.verify(handler).doubleCell(eq("B10"), eq(42803.0d), isNull(),
any(ExcelNumberFormat.class));
+ ordered.verify(handler).endRow(9);
+
+ ordered.verify(handler).startRow(10);
+ ordered.verify(handler).stringCell(eq("A11"), eq("comment"), isNull());
+ ordered.verify(handler).stringCell(eq("B11"), eq("contents"),
notNull(XSSFComment.class));
+ ordered.verify(handler).endRow(10);
+
+ ordered.verify(handler).startRow(11);
+ ordered.verify(handler).stringCell(eq("A12"), eq("hyperlink"),
isNull());
+ ordered.verify(handler).stringCell(eq("B12"), eq("tika_link"),
isNull());
+ ordered.verify(handler).endRow(11);
+
+ ordered.verify(handler).startRow(12);
+ ordered.verify(handler).stringCell(eq("A13"), eq("formula"), isNull());
+ ordered.verify(handler).doubleCell(eq("B13"), eq(4.0d), isNull(),
any(ExcelNumberFormat.class));
+ ordered.verify(handler).doubleCell(eq("C13"), eq(2.0d), isNull(),
any(ExcelNumberFormat.class));
+ ordered.verify(handler).endRow(12);
+
+ ordered.verify(handler).startRow(13);
+ ordered.verify(handler).stringCell(eq("A14"), eq("formulaErr"),
isNull());
+ ordered.verify(handler).errorCell(eq("B14"), eq(FormulaError.NAME),
isNull());
+ ordered.verify(handler).endRow(13);
+
+ ordered.verify(handler).startRow(14);
+ ordered.verify(handler).stringCell(eq("A15"), eq("formulaFloat"),
isNull());
+ ordered.verify(handler).doubleCell(eq("B15"), eq(0.5d), isNull(),
any(ExcelNumberFormat.class));
+ ordered.verify(handler).stringCell(eq("D15"), eq("March"), isNull());
+ ordered.verify(handler).stringCell(eq("E15"), eq("April"), isNull());
+ ordered.verify(handler).endRow(14);
+
+ ordered.verify(handler).startRow(15);
+ ordered.verify(handler).stringCell(eq("A16"), eq("customFormat1"),
isNull());
+ ordered.verify(handler).stringCell(eq("B16"), eq(" 46/1963"),
isNull());
+ ordered.verify(handler).stringCell(eq("C16"), eq("merchant1"),
isNull());
+ ordered.verify(handler).doubleCell(eq("D16"), eq(1.0d), isNull(),
any(ExcelNumberFormat.class));
+ ordered.verify(handler).doubleCell(eq("E16"), eq(3.0d), isNull(),
any(ExcelNumberFormat.class));
+ ordered.verify(handler).endRow(15);
+
+ ordered.verify(handler).startRow(16);
+ ordered.verify(handler).stringCell(eq("A17"), eq("customFormat2"),
isNull());
+ ordered.verify(handler).stringCell(eq("B17"), eq(" 3/128"), isNull());
+ ordered.verify(handler).stringCell(eq("C17"), eq("merchant2"),
isNull());
+ ordered.verify(handler).doubleCell(eq("D17"), eq(2.0d), isNull(),
any(ExcelNumberFormat.class));
+ ordered.verify(handler).doubleCell(eq("E17"), eq(4.0d), isNull(),
any(ExcelNumberFormat.class));
+ ordered.verify(handler).endRow(16);
+
+ ordered.verify(handler).startRow(20);
+ ordered.verify(handler).stringCell(eq("C21"), eq("text test"),
isNull());
+ ordered.verify(handler).endRow(20);
+
+ ordered.verify(handler).startRow(22);
+ ordered.verify(handler).stringCell(eq("A23"), isNull(),
notNull(XSSFComment.class));
+ ordered.verify(handler).endRow(22);
+
+ ordered.verify(handler).startRow(23);
+ ordered.verify(handler).stringCell(eq("C24"), isNull(),
notNull(XSSFComment.class));
+ ordered.verify(handler).endRow(23);
+
+ ordered.verify(handler).startRow(27);
+ ordered.verify(handler).stringCell(eq("B28"), isNull(),
notNull(XSSFComment.class));
+ ordered.verify(handler).endRow(27);
+
+ ordered.verify(handler).startRow(29);
+ ordered.verify(handler).stringCell(eq("B30"), eq("the"), isNull());
+ ordered.verify(handler).stringCell(eq("C30"), isNull(),
notNull(XSSFComment.class));
+ ordered.verify(handler).endRow(29);
+
+ ordered.verify(handler).startRow(32);
+ ordered.verify(handler).stringCell(eq("B33"), eq("the"), isNull());
+ ordered.verify(handler).stringCell(eq("C33"), isNull(),
notNull(XSSFComment.class));
+ ordered.verify(handler).stringCell(eq("D33"), eq("quick"), isNull());
+ ordered.verify(handler).endRow(32);
+
+ ordered.verify(handler).startRow(34);
+ ordered.verify(handler).stringCell(eq("B35"), eq("comment6"),
notNull(XSSFComment.class));
+ ordered.verify(handler).endRow(34);
+
+ ordered.verify(handler).startRow(64);
+ ordered.verify(handler).stringCell(eq("I65"), isNull(),
notNull(XSSFComment.class));
+ ordered.verify(handler).endRow(64);
+
+ ordered.verify(handler).startRow(65);
+ ordered.verify(handler).stringCell(eq("I66"), isNull(),
notNull(XSSFComment.class));
+ ordered.verify(handler).endRow(65);
+
+ ordered.verify(handler).headerFooter(eq("OddLeftHeader OddCenterHeader
OddRightHeader"), eq(true), eq("header"));
+ ordered.verify(handler).headerFooter(eq("OddLeftFooter OddCenterFooter
OddRightFooter"), eq(false), eq("footer"));
+ ordered.verify(handler).headerFooter(eq("EvenLeftHeader
EvenCenterHeader EvenRightHeader\n"), eq(true), eq("evenHeader"));
+ ordered.verify(handler).headerFooter(eq("EvenLeftFooter
EvenCenterFooter EvenRightFooter"), eq(false), eq("evenFooter"));
+ ordered.verify(handler).headerFooter(eq("FirstPageLeftHeader
FirstPageCenterHeader FirstPageRightHeader"), eq(true), eq("firstHeader"));
+ ordered.verify(handler).headerFooter(eq("FirstPageLeftFooter
FirstPageCenterFooter FirstPageRightFooter"), eq(false), eq("firstFooter"));
+ ordered.verifyNoMoreInteractions();
+ }
+
+ @Test
+ void testCommentsXSSFBSheetContentsHandler() throws Exception {
+ XSSFBSheetHandler.XSSFBSheetContentsHandler handler =
mockSheetContentsHandler();
+ readAllSheetsFromWorkbook("comments.xlsb", handler);
+
+ InOrder ordered = inOrder(handler);
+ ordered.verify(handler).startRow(0);
+ ordered.verify(handler).stringCell(eq("A1"), isNull(),
+ argThat(commentWith("Sven Nissel", "comment top row1
(index0)")));
+ ordered.verify(handler).stringCell(eq("B1"), eq("row1"), isNull());
+ ordered.verify(handler).endRow(0);
+ ordered.verify(handler).startRow(1);
+ ordered.verify(handler).stringCell(eq("A2"), isNull(),
+ argThat(commentWith("Allison, Timothy B.", "Allison, Timothy
B.:\ncomment row2 (index1)")));
+ ordered.verify(handler).endRow(1);
+ ordered.verify(handler).startRow(2);
+ ordered.verify(handler).stringCell(eq("A3"), eq("row3"),
+ argThat(commentWith("Sven Nissel", "comment top row3
(index2)")));
+ ordered.verify(handler).stringCell(eq("B3"), eq("row3"), isNull());
+ ordered.verify(handler).endRow(2);
+ ordered.verify(handler).startRow(3);
+ ordered.verify(handler).stringCell(eq("A4"), isNull(),
+ argThat(commentWith("Sven Nissel", "comment top row4
(index3)")));
+ ordered.verify(handler).stringCell(eq("B4"), eq("row4"), isNull());
+ ordered.verify(handler).endRow(3);
+ }
+
+ @Test
+ void testDateXSSFBSheetContentsHandler() throws Exception {
+ XSSFBSheetHandler.XSSFBSheetContentsHandler handler =
mockSheetContentsHandler();
+ readAllSheetsFromWorkbook("date.xlsb", handler);
+
+ InOrder ordered = inOrder(handler);
+ ArgumentCaptor<ExcelNumberFormat> numberFormat =
ArgumentCaptor.forClass(ExcelNumberFormat.class);
+ ordered.verify(handler).startRow(0);
+ ordered.verify(handler).doubleCell(eq("A1"), eq(41286.0d), isNull(),
numberFormat.capture());
+ ordered.verify(handler).endRow(0);
+ ExcelNumberFormat format = numberFormat.getValue();
+ assertNotNull(format);
+ assertEquals(14, format.getIdx());
+ assertEquals("m/d/yy", format.getFormat());
+ ordered.verifyNoMoreInteractions();
+ DataFormatter df = new DataFormatter();
+ assertEquals("1/12/13", df.formatRawCellContents(41286.0d,
format.getIdx(), format.getFormat()));
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]