<!-- Don't forget to update status.xml too! -->
<release version="3.1.1-alpha1" date="2008-??-??">
+ <action dev="POI-DEVELOPERS" type="fix">45365 - Handle more excel number formatting rules in FormatTrackingHSSFListener / XLS2CSVmra</action>
<action dev="POI-DEVELOPERS" type="fix">45373 - Improve the performance of HSSFSheet.shiftRows</action>
<action dev="POI-DEVELOPERS" type="fix">45367 - Fixed bug when last row removed from sheet is row zero</action>
<action dev="POI-DEVELOPERS" type="fix">45348 - Tweaks to RVA formula logic</action>
<!-- Don't forget to update changes.xml too! -->
<changes>
<release version="3.1.1-alpha1" date="2008-??-??">
+ <action dev="POI-DEVELOPERS" type="fix">45365 - Handle more excel number formatting rules in FormatTrackingHSSFListener / XLS2CSVmra</action>
<action dev="POI-DEVELOPERS" type="fix">45373 - Improve the performance of HSSFSheet.shiftRows</action>
<action dev="POI-DEVELOPERS" type="fix">45367 - Fixed bug when last row removed from sheet is row zero</action>
<action dev="POI-DEVELOPERS" type="fix">45348 - Tweaks to RVA formula logic</action>
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
-import java.text.DateFormat;
-import java.text.DecimalFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
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.CellValueRecordInterface;
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.Record;
import org.apache.poi.hssf.record.SSTRecord;
import org.apache.poi.hssf.record.StringRecord;
-import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
nextRow = frec.getRow();
nextColumn = frec.getColumn();
} else {
- thisStr = formatNumberDateCell(frec, frec.getValue());
+ thisStr = formatListener.formatNumberDateCell(frec);
}
} else {
thisStr = '"' +
thisColumn = numrec.getColumn();
// Format
- thisStr = formatNumberDateCell(numrec, numrec.getValue());
+ thisStr = formatListener.formatNumberDateCell(numrec);
break;
case RKRecord.sid:
RKRecord rkrec = (RKRecord) record;
}
}
- /**
- * Formats a number or date cell, be that a real number, or the
- * answer to a formula
- */
- private String formatNumberDateCell(CellValueRecordInterface cell, double value) {
- // Get the built in format, if there is one
- int formatIndex = formatListener.getFormatIndex(cell);
- String formatString = formatListener.getFormatString(cell);
-
- if(formatString == null) {
- return Double.toString(value);
- } else {
- // Is it a date?
- if(HSSFDateUtil.isADateFormat(formatIndex,formatString) &&
- HSSFDateUtil.isValidExcelDate(value)) {
- // Java wants M not m for month
- formatString = formatString.replace('m','M');
- // Change \- into -, if it's there
- formatString = formatString.replaceAll("\\\\-","-");
-
- // Format as a date
- Date d = HSSFDateUtil.getJavaDate(value, false);
- DateFormat df = new SimpleDateFormat(formatString);
- return df.format(d);
- } else {
- if(formatString == "General") {
- // Some sort of wierd default
- return Double.toString(value);
- }
-
- // Format as a number
- DecimalFormat df = new DecimalFormat(formatString);
- return df.format(value);
- }
- }
- }
-
-
public static void main(String[] args) throws Exception {
if(args.length < 1) {
System.err.println("Use:");
==================================================================== */
package org.apache.poi.hssf.eventusermodel;
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Date;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import org.apache.poi.hssf.record.CellValueRecordInterface;
import org.apache.poi.hssf.record.ExtendedFormatRecord;
import org.apache.poi.hssf.record.FormatRecord;
+import org.apache.poi.hssf.record.FormulaRecord;
+import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
+import org.apache.poi.hssf.usermodel.HSSFDateUtil;
/**
* A proxy HSSFListener that keeps track of the document
}
}
+ /**
+ * Formats the given numeric of date Cell's contents
+ * as a String, in as close as we can to the way
+ * that Excel would do so.
+ * Uses the various format records to manage this.
+ *
+ * TODO - move this to a central class in such a
+ * way that hssf.usermodel can make use of it too
+ */
+ public String formatNumberDateCell(CellValueRecordInterface cell) {
+ double value;
+ if(cell instanceof NumberRecord) {
+ value = ((NumberRecord)cell).getValue();
+ } else if(cell instanceof FormulaRecord) {
+ value = ((FormulaRecord)cell).getValue();
+ } else {
+ throw new IllegalArgumentException("Unsupported CellValue Record passed in " + cell);
+ }
+
+ // Get the built in format, if there is one
+ int formatIndex = getFormatIndex(cell);
+ String formatString = getFormatString(cell);
+
+ if(formatString == null) {
+ return Double.toString(value);
+ } else {
+ // Is it a date?
+ if(HSSFDateUtil.isADateFormat(formatIndex,formatString) &&
+ HSSFDateUtil.isValidExcelDate(value)) {
+ // Java wants M not m for month
+ formatString = formatString.replace('m','M');
+ // Change \- into -, if it's there
+ formatString = formatString.replaceAll("\\\\-","-");
+
+ // Format as a date
+ Date d = HSSFDateUtil.getJavaDate(value, false);
+ DateFormat df = new SimpleDateFormat(formatString);
+ return df.format(d);
+ } else {
+ if(formatString == "General") {
+ // Some sort of wierd default
+ return Double.toString(value);
+ }
+ if(formatString == "0.00E+00") {
+ // This seems to mean output as a normal double
+ return Double.toString(value);
+ }
+
+ // Format as a number
+ DecimalFormat df = new DecimalFormat(formatString);
+ return df.format(value);
+ }
+ }
+ }
+
/**
* Returns the format string, eg $##.##, for the
* given number format index.
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.record.CellValueRecordInterface;
+import org.apache.poi.hssf.record.FormulaRecord;
+import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
/**
*/
public final class TestFormatTrackingHSSFListener extends TestCase {
private FormatTrackingHSSFListener listener;
-
- public void setUp() {
+ private MockHSSFListener mockListen;
+
+ private void processFile(String filename) throws Exception {
HSSFRequest req = new HSSFRequest();
- MockHSSFListener mockListen = new MockHSSFListener();
+ mockListen = new MockHSSFListener();
listener = new FormatTrackingHSSFListener(mockListen);
req.addListenerForAllRecords(listener);
HSSFEventFactory factory = new HSSFEventFactory();
try {
- InputStream is = HSSFTestDataSamples.openSampleFileStream("MissingBits.xls");
+ InputStream is = HSSFTestDataSamples.openSampleFileStream(filename);
POIFSFileSystem fs = new POIFSFileSystem(is);
factory.processWorkbookEvents(req, fs);
} catch (IOException e) {
}
public void testFormats() throws Exception {
+ processFile("MissingBits.xls");
+
assertEquals("_(*#,##0_);_(*(#,##0);_(* \"-\"_);_(@_)", listener.getFormatString(41));
assertEquals("_($*#,##0_);_($*(#,##0);_($* \"-\"_);_(@_)", listener.getFormatString(42));
assertEquals("_(*#,##0.00_);_(*(#,##0.00);_(*\"-\"??_);_(@_)", listener.getFormatString(43));
}
+ /**
+ * Ensure that all number and formula records can be
+ * turned into strings without problems
+ */
+ public void testTurnToString() throws Exception {
+ processFile("45365.xls");
+
+ for(int i=0; i<mockListen._records.size(); i++) {
+ Record r = (Record)mockListen._records.get(i);
+ CellValueRecordInterface cvr = null;
+
+ if(r instanceof NumberRecord) {
+ cvr = (CellValueRecordInterface)r;
+ }
+ if(r instanceof FormulaRecord) {
+ cvr = (CellValueRecordInterface)r;
+ }
+
+ if(cvr != null) {
+ // Should always give us a string
+ String s = listener.formatNumberDateCell(cvr);
+ assertNotNull(s);
+ assertTrue(s.length() > 0);
+ }
+ }
+
+ // TODO - test some specific format strings
+ }
+
private static final class MockHSSFListener implements HSSFListener {
public MockHSSFListener() {}
private final List _records = new ArrayList();