Fix bug #45365 - Handle more excel number formatting rules in FormatTrackingHSSFListener / XLS2CSVmra

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@675671 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2008-07-10 18:41:25 +00:00
parent f6730d9a3a
commit 81f9610e04
6 changed files with 105 additions and 50 deletions

View File

@ -37,6 +37,7 @@
<!-- Don't forget to update status.xml too! --> <!-- Don't forget to update status.xml too! -->
<release version="3.1.1-alpha1" date="2008-??-??"> <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">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">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> <action dev="POI-DEVELOPERS" type="fix">45348 - Tweaks to RVA formula logic</action>

View File

@ -34,6 +34,7 @@
<!-- Don't forget to update changes.xml too! --> <!-- Don't forget to update changes.xml too! -->
<changes> <changes>
<release version="3.1.1-alpha1" date="2008-??-??"> <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">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">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> <action dev="POI-DEVELOPERS" type="fix">45348 - Tweaks to RVA formula logic</action>

View File

@ -20,10 +20,6 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; 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.FormatTrackingHSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFEventFactory; import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
@ -37,7 +33,6 @@ import org.apache.poi.hssf.model.FormulaParser;
import org.apache.poi.hssf.record.BOFRecord; import org.apache.poi.hssf.record.BOFRecord;
import org.apache.poi.hssf.record.BlankRecord; import org.apache.poi.hssf.record.BlankRecord;
import org.apache.poi.hssf.record.BoolErrRecord; 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.FormulaRecord;
import org.apache.poi.hssf.record.LabelRecord; import org.apache.poi.hssf.record.LabelRecord;
import org.apache.poi.hssf.record.LabelSSTRecord; import org.apache.poi.hssf.record.LabelSSTRecord;
@ -47,7 +42,6 @@ import org.apache.poi.hssf.record.RKRecord;
import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.SSTRecord; import org.apache.poi.hssf.record.SSTRecord;
import org.apache.poi.hssf.record.StringRecord; 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.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
@ -180,7 +174,7 @@ public class XLS2CSVmra implements HSSFListener {
nextRow = frec.getRow(); nextRow = frec.getRow();
nextColumn = frec.getColumn(); nextColumn = frec.getColumn();
} else { } else {
thisStr = formatNumberDateCell(frec, frec.getValue()); thisStr = formatListener.formatNumberDateCell(frec);
} }
} else { } else {
thisStr = '"' + thisStr = '"' +
@ -231,7 +225,7 @@ public class XLS2CSVmra implements HSSFListener {
thisColumn = numrec.getColumn(); thisColumn = numrec.getColumn();
// Format // Format
thisStr = formatNumberDateCell(numrec, numrec.getValue()); thisStr = formatListener.formatNumberDateCell(numrec);
break; break;
case RKRecord.sid: case RKRecord.sid:
RKRecord rkrec = (RKRecord) record; RKRecord rkrec = (RKRecord) record;
@ -290,44 +284,6 @@ public class XLS2CSVmra implements HSSFListener {
} }
} }
/**
* 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 { public static void main(String[] args) throws Exception {
if(args.length < 1) { if(args.length < 1) {
System.err.println("Use:"); System.err.println("Use:");

View File

@ -16,7 +16,11 @@
==================================================================== */ ==================================================================== */
package org.apache.poi.hssf.eventusermodel; 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.ArrayList;
import java.util.Date;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -24,8 +28,11 @@ import java.util.Map;
import org.apache.poi.hssf.record.CellValueRecordInterface; import org.apache.poi.hssf.record.CellValueRecordInterface;
import org.apache.poi.hssf.record.ExtendedFormatRecord; import org.apache.poi.hssf.record.ExtendedFormatRecord;
import org.apache.poi.hssf.record.FormatRecord; 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.record.Record;
import org.apache.poi.hssf.usermodel.HSSFDataFormat; import org.apache.poi.hssf.usermodel.HSSFDataFormat;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
/** /**
* A proxy HSSFListener that keeps track of the document * A proxy HSSFListener that keeps track of the document
@ -69,6 +76,61 @@ public class FormatTrackingHSSFListener implements HSSFListener {
} }
} }
/**
* 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 * Returns the format string, eg $##.##, for the
* given number format index. * given number format index.

Binary file not shown.

View File

@ -24,6 +24,9 @@ import java.util.List;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples; 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.hssf.record.Record;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
/** /**
@ -31,16 +34,17 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
*/ */
public final class TestFormatTrackingHSSFListener extends TestCase { public final class TestFormatTrackingHSSFListener extends TestCase {
private FormatTrackingHSSFListener listener; private FormatTrackingHSSFListener listener;
private MockHSSFListener mockListen;
public void setUp() { private void processFile(String filename) throws Exception {
HSSFRequest req = new HSSFRequest(); HSSFRequest req = new HSSFRequest();
MockHSSFListener mockListen = new MockHSSFListener(); mockListen = new MockHSSFListener();
listener = new FormatTrackingHSSFListener(mockListen); listener = new FormatTrackingHSSFListener(mockListen);
req.addListenerForAllRecords(listener); req.addListenerForAllRecords(listener);
HSSFEventFactory factory = new HSSFEventFactory(); HSSFEventFactory factory = new HSSFEventFactory();
try { try {
InputStream is = HSSFTestDataSamples.openSampleFileStream("MissingBits.xls"); InputStream is = HSSFTestDataSamples.openSampleFileStream(filename);
POIFSFileSystem fs = new POIFSFileSystem(is); POIFSFileSystem fs = new POIFSFileSystem(is);
factory.processWorkbookEvents(req, fs); factory.processWorkbookEvents(req, fs);
} catch (IOException e) { } catch (IOException e) {
@ -49,11 +53,42 @@ public final class TestFormatTrackingHSSFListener extends TestCase {
} }
public void testFormats() throws Exception { public void testFormats() throws Exception {
processFile("MissingBits.xls");
assertEquals("_(*#,##0_);_(*(#,##0);_(* \"-\"_);_(@_)", listener.getFormatString(41)); assertEquals("_(*#,##0_);_(*(#,##0);_(* \"-\"_);_(@_)", listener.getFormatString(41));
assertEquals("_($*#,##0_);_($*(#,##0);_($* \"-\"_);_(@_)", listener.getFormatString(42)); assertEquals("_($*#,##0_);_($*(#,##0);_($* \"-\"_);_(@_)", listener.getFormatString(42));
assertEquals("_(*#,##0.00_);_(*(#,##0.00);_(*\"-\"??_);_(@_)", listener.getFormatString(43)); 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 { private static final class MockHSSFListener implements HSSFListener {
public MockHSSFListener() {} public MockHSSFListener() {}
private final List _records = new ArrayList(); private final List _records = new ArrayList();