package org.apache.poi.hssf.eventusermodel;
-import org.apache.poi.hssf.eventusermodel.HSSFListener;
import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;
import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingRowDummyRecord;
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.FormulaRecord;
-import org.apache.poi.hssf.record.LabelRecord;
-import org.apache.poi.hssf.record.LabelSSTRecord;
+import org.apache.poi.hssf.record.CellValueRecordInterface;
import org.apache.poi.hssf.record.NoteRecord;
-import org.apache.poi.hssf.record.NumberRecord;
-import org.apache.poi.hssf.record.RKRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RowRecord;
+import org.apache.poi.hssf.record.SharedFormulaRecord;
/**
* <p>A HSSFListener which tracks rows and columns, and will
* file, or was skipped from being written as it was
* blank.
*/
-public class MissingRecordAwareHSSFListener implements HSSFListener {
+public final class MissingRecordAwareHSSFListener implements HSSFListener {
private HSSFListener childListener;
// Need to have different counters for cell rows and
// row rows, as you sometimes get a RowRecord in the
// middle of some cells, and that'd break everything
- private int lastRowRow = -1;
+ private int lastRowRow;
- private int lastCellRow = -1;
- private int lastCellColumn = -1;
+ private int lastCellRow;
+ private int lastCellColumn;
/**
* Constructs a new MissingRecordAwareHSSFListener, which
* @param listener The HSSFListener to pass records on to
*/
public MissingRecordAwareHSSFListener(HSSFListener listener) {
+ resetCounts();
childListener = listener;
}
public void processRecord(Record record) {
- int thisRow = -1;
- int thisColumn = -1;
-
- switch (record.getSid())
- {
- // the BOFRecord can represent either the beginning of a sheet or the workbook
- case BOFRecord.sid:
- BOFRecord bof = (BOFRecord) record;
- if (bof.getType() == bof.TYPE_WORKBOOK)
- {
- // Reset the row and column counts - new workbook
- lastRowRow = -1;
- lastCellRow = -1;
- lastCellColumn = -1;
- //System.out.println("Encountered workbook");
- } else if (bof.getType() == bof.TYPE_WORKSHEET)
- {
- // Reset the row and column counts - new sheet
- lastRowRow = -1;
- lastCellRow = -1;
- lastCellColumn = -1;
- //System.out.println("Encountered sheet reference");
- }
- break;
- case BoundSheetRecord.sid:
- BoundSheetRecord bsr = (BoundSheetRecord) record;
- //System.out.println("New sheet named: " + bsr.getSheetname());
- break;
- case RowRecord.sid:
- RowRecord rowrec = (RowRecord) record;
- //System.out.println("Row " + rowrec.getRowNumber() + " found, first column at "
- // + rowrec.getFirstCol() + " last column at " + rowrec.getLastCol());
-
- // If there's a jump in rows, fire off missing row records
- if(lastRowRow+1 < rowrec.getRowNumber()) {
- for(int i=(lastRowRow+1); i<rowrec.getRowNumber(); i++) {
- MissingRowDummyRecord dr = new MissingRowDummyRecord(i);
- childListener.processRecord(dr);
- }
- }
-
- // Record this as the last row we saw
- lastRowRow = rowrec.getRowNumber();
- break;
-
-
- // These are all the "cell" records
-
- case BlankRecord.sid:
- BlankRecord brec = (BlankRecord) record;
- thisRow = brec.getRow();
- thisColumn = brec.getColumn();
- break;
- case BoolErrRecord.sid:
- BoolErrRecord berec = (BoolErrRecord) record;
- thisRow = berec.getRow();
- thisColumn = berec.getColumn();
- break;
- case FormulaRecord.sid:
- FormulaRecord frec = (FormulaRecord) record;
- thisRow = frec.getRow();
- thisColumn = frec.getColumn();
- break;
- case LabelRecord.sid:
- LabelRecord lrec = (LabelRecord) record;
- thisRow = lrec.getRow();
- thisColumn = lrec.getColumn();
- //System.out.println("Cell found containing String "
- // + " at row " + lrec.getRow() + " and column " + lrec.getColumn());
- break;
- case LabelSSTRecord.sid:
- LabelSSTRecord lsrec = (LabelSSTRecord) record;
- thisRow = lsrec.getRow();
- thisColumn = lsrec.getColumn();
- //System.out.println("Cell found containing String "
- // + " at row " + lsrec.getRow() + " and column " + lsrec.getColumn());
- break;
- case NoteRecord.sid:
- NoteRecord nrec = (NoteRecord) record;
- thisRow = nrec.getRow();
- thisColumn = nrec.getColumn();
- break;
- case NumberRecord.sid:
- NumberRecord numrec = (NumberRecord) record;
- thisRow = numrec.getRow();
- thisColumn = numrec.getColumn();
- //System.out.println("Cell found with value " + numrec.getValue()
- // + " at row " + numrec.getRow() + " and column " + numrec.getColumn());
- break;
- case RKRecord.sid:
- RKRecord rkrec = (RKRecord) record;
- thisRow = rkrec.getRow();
- thisColumn = rkrec.getColumn();
- break;
- default:
- //System.out.println(record.getClass());
- break;
- }
-
+ int thisRow;
+ int thisColumn;
+
+
+ if (record instanceof CellValueRecordInterface) {
+ CellValueRecordInterface valueRec = (CellValueRecordInterface) record;
+ thisRow = valueRec.getRow();
+ thisColumn = valueRec.getColumn();
+ } else {
+ thisRow = -1;
+ thisColumn = -1;
+
+ switch (record.getSid()) {
+ // the BOFRecord can represent either the beginning of a sheet or
+ // the workbook
+ case BOFRecord.sid:
+ BOFRecord bof = (BOFRecord) record;
+ if (bof.getType() == bof.TYPE_WORKBOOK || bof.getType() == bof.TYPE_WORKSHEET) {
+ // Reset the row and column counts - new workbook / worksheet
+ resetCounts();
+ }
+ break;
+ case RowRecord.sid:
+ RowRecord rowrec = (RowRecord) record;
+ //System.out.println("Row " + rowrec.getRowNumber() + " found, first column at "
+ // + rowrec.getFirstCol() + " last column at " + rowrec.getLastCol());
+
+ // If there's a jump in rows, fire off missing row records
+ if (lastRowRow + 1 < rowrec.getRowNumber()) {
+ for (int i = (lastRowRow + 1); i < rowrec.getRowNumber(); i++) {
+ MissingRowDummyRecord dr = new MissingRowDummyRecord(i);
+ childListener.processRecord(dr);
+ }
+ }
+
+ // Record this as the last row we saw
+ lastRowRow = rowrec.getRowNumber();
+ break;
+
+ case SharedFormulaRecord.sid:
+ // SharedFormulaRecord occurs after the first FormulaRecord of the cell range.
+ // There are probably (but not always) more cell records after this
+ // - so don't fire off the LastCellOfRowDummyRecord yet
+ childListener.processRecord(record);
+ return;
+ case NoteRecord.sid:
+ NoteRecord nrec = (NoteRecord) record;
+ thisRow = nrec.getRow();
+ thisColumn = nrec.getColumn();
+ break;
+ }
+ }
// If we're on cells, and this cell isn't in the same
// row as the last one, then fire the
- // dummy end-of-row records?
+ // dummy end-of-row records
if(thisRow != lastCellRow && lastCellRow > -1) {
for(int i=lastCellRow; i<thisRow; i++) {
int cols = -1;
if(i == lastCellRow) {
cols = lastCellColumn;
}
- LastCellOfRowDummyRecord r = new LastCellOfRowDummyRecord(i, cols);
- childListener.processRecord(r);
+ childListener.processRecord(new LastCellOfRowDummyRecord(i, cols));
}
}
// If we've just finished with the cells, then fire the
- // final dummy end-of-row record
+ // final dummy end-of-row record
if(lastCellRow != -1 && lastCellColumn != -1 && thisRow == -1) {
- LastCellOfRowDummyRecord r = new LastCellOfRowDummyRecord(lastCellRow, lastCellColumn);
- childListener.processRecord(r);
+ childListener.processRecord(new LastCellOfRowDummyRecord(lastCellRow, lastCellColumn));
lastCellRow = -1;
lastCellColumn = -1;
}
// If there's a gap in the cells, then fire
- // the dummy cell records?
- if(lastCellColumn != (thisColumn-1)) {
+ // the dummy cell records
+ if(lastCellColumn != thisColumn-1) {
for(int i=lastCellColumn+1; i<thisColumn; i++) {
- MissingCellDummyRecord r = new MissingCellDummyRecord(thisRow, i);
- childListener.processRecord(r);
+ childListener.processRecord(new MissingCellDummyRecord(thisRow, i));
}
}
lastCellColumn = thisColumn;
lastCellRow = thisRow;
}
-
+
childListener.processRecord(record);
}
+
+ private void resetCounts() {
+ lastRowRow = -1;
+ lastCellRow = -1;
+ lastCellColumn = -1;
+ }
}
import java.util.ArrayList;
import java.util.List;
+import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.LabelSSTRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RowRecord;
+import org.apache.poi.hssf.record.SharedFormulaRecord;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
/**
* Tests for MissingRecordAwareHSSFListener
private Record[] r;
- public void openNormal() {
- HSSFRequest req = new HSSFRequest();
- MockHSSFListener mockListen = new MockHSSFListener();
- MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(mockListen);
- req.addListenerForAllRecords(listener);
-
- HSSFEventFactory factory = new HSSFEventFactory();
- try {
- InputStream is = HSSFTestDataSamples.openSampleFileStream("MissingBits.xls");
- POIFSFileSystem fs = new POIFSFileSystem(is);
- factory.processWorkbookEvents(req, fs);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
-
- r = mockListen.getRecords();
- assertTrue(r.length > 100);
- }
- public void openAlt() {
+ private void readRecords(String sampleFileName) {
HSSFRequest req = new HSSFRequest();
MockHSSFListener mockListen = new MockHSSFListener();
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(mockListen);
HSSFEventFactory factory = new HSSFEventFactory();
try {
- InputStream is = HSSFTestDataSamples.openSampleFileStream("MRExtraLines.xls");
+ InputStream is = HSSFTestDataSamples.openSampleFileStream(sampleFileName);
POIFSFileSystem fs = new POIFSFileSystem(is);
factory.processWorkbookEvents(req, fs);
} catch (IOException e) {
r = mockListen.getRecords();
assertTrue(r.length > 100);
}
+ public void openNormal() {
+ readRecords("MissingBits.xls");
+ }
- public void testMissingRowRecords() throws Exception {
+ public void testMissingRowRecords() {
openNormal();
// We have rows 0, 1, 2, 20 and 21
assertEquals(19, mr.getRowNumber());
}
- public void testEndOfRowRecords() throws Exception {
+ public void testEndOfRowRecords() {
openNormal();
// Find the cell at 0,0
}
- public void testMissingCellRecords() throws Exception {
+ public void testMissingCellRecords() {
openNormal();
// Find the cell at 0,0
// Make sure we don't put in any extra new lines
// that aren't already there
- public void testNoExtraNewLines() throws Exception {
+ public void testNoExtraNewLines() {
// Load a different file
- openAlt();
-
-
// This file has has something in lines 1-33
- List lcor = new ArrayList();
+ readRecords("MRExtraLines.xls");
+
+ int rowCount=0;
for(int i=0; i<r.length; i++) {
- if(r[i] instanceof LastCellOfRowDummyRecord)
- lcor.add( (LastCellOfRowDummyRecord)r[i] );
+ if(r[i] instanceof LastCellOfRowDummyRecord) {
+ LastCellOfRowDummyRecord eor = (LastCellOfRowDummyRecord) r[i];
+ assertEquals(rowCount, eor.getRow());
+ rowCount++;
+ }
}
-
// Check we got the 33 rows
- assertEquals(33, lcor.size());
- LastCellOfRowDummyRecord[] rowEnds = (LastCellOfRowDummyRecord[])
- lcor.toArray(new LastCellOfRowDummyRecord[lcor.size()]);
- assertEquals(33, rowEnds.length);
-
- // And check they have the right stuff in them,
- // no repeats
- for(int i=0; i<rowEnds.length; i++) {
- assertEquals(i, rowEnds[i].getRow());
- }
+ assertEquals(33, rowCount);
}
private static final class MockHSSFListener implements HSSFListener {
return result;
}
}
+
+ /**
+ * Make sure that the presence of shared formulas does not cause extra
+ * end-of-row records.
+ */
+ public void testEndOfRow_bug45672() {
+ readRecords("ex45672.xls");
+ Record[] rr = r;
+ int eorCount=0;
+ int sfrCount=0;
+ for (int i = 0; i < rr.length; i++) {
+ Record record = rr[i];
+ if (record instanceof SharedFormulaRecord) {
+ sfrCount++;
+ }
+ if (record instanceof LastCellOfRowDummyRecord) {
+ eorCount++;
+ }
+ }
+ if (eorCount == 2) {
+ throw new AssertionFailedError("Identified bug 45672");
+ }
+ assertEquals(1, eorCount);
+ assertEquals(1, sfrCount);
+ }
}