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:
parent
f6730d9a3a
commit
81f9610e04
@ -37,6 +37,7 @@
|
||||
|
||||
<!-- 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>
|
||||
|
@ -34,6 +34,7 @@
|
||||
<!-- 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>
|
||||
|
@ -20,10 +20,6 @@ import java.io.FileInputStream;
|
||||
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;
|
||||
@ -37,7 +33,6 @@ import org.apache.poi.hssf.model.FormulaParser;
|
||||
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;
|
||||
@ -47,7 +42,6 @@ import org.apache.poi.hssf.record.RKRecord;
|
||||
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;
|
||||
|
||||
@ -180,7 +174,7 @@ public class XLS2CSVmra implements HSSFListener {
|
||||
nextRow = frec.getRow();
|
||||
nextColumn = frec.getColumn();
|
||||
} else {
|
||||
thisStr = formatNumberDateCell(frec, frec.getValue());
|
||||
thisStr = formatListener.formatNumberDateCell(frec);
|
||||
}
|
||||
} else {
|
||||
thisStr = '"' +
|
||||
@ -231,7 +225,7 @@ public class XLS2CSVmra implements HSSFListener {
|
||||
thisColumn = numrec.getColumn();
|
||||
|
||||
// Format
|
||||
thisStr = formatNumberDateCell(numrec, numrec.getValue());
|
||||
thisStr = formatListener.formatNumberDateCell(numrec);
|
||||
break;
|
||||
case RKRecord.sid:
|
||||
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 {
|
||||
if(args.length < 1) {
|
||||
System.err.println("Use:");
|
||||
|
@ -16,7 +16,11 @@
|
||||
==================================================================== */
|
||||
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;
|
||||
@ -24,8 +28,11 @@ 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
|
||||
@ -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
|
||||
* given number format index.
|
||||
|
BIN
src/testcases/org/apache/poi/hssf/data/45365.xls
Normal file
BIN
src/testcases/org/apache/poi/hssf/data/45365.xls
Normal file
Binary file not shown.
@ -24,6 +24,9 @@ import java.util.List;
|
||||
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;
|
||||
/**
|
||||
@ -31,16 +34,17 @@ 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) {
|
||||
@ -49,11 +53,42 @@ public final class TestFormatTrackingHSSFListener extends TestCase {
|
||||
}
|
||||
|
||||
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();
|
||||
|
Loading…
Reference in New Issue
Block a user