]> source.dussan.org Git - poi.git/commitdiff
Fix bug #45365 - Handle more excel number formatting rules in FormatTrackingHSSFListe...
authorNick Burch <nick@apache.org>
Thu, 10 Jul 2008 18:41:25 +0000 (18:41 +0000)
committerNick Burch <nick@apache.org>
Thu, 10 Jul 2008 18:41:25 +0000 (18:41 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@675671 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/status.xml
src/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java
src/java/org/apache/poi/hssf/eventusermodel/FormatTrackingHSSFListener.java
src/testcases/org/apache/poi/hssf/data/45365.xls [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/eventusermodel/TestFormatTrackingHSSFListener.java

index 16a82aa3aeb6b6923614782850a9651803aef23d..808bea2a9c3f117a77eb5537c35f5cc84741f14d 100644 (file)
@@ -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>
index 7143b98d78c22e8f6c2897c4f0371e9fb3a314dd..21d279ada1feb164d518e980f216d5abc869b254 100644 (file)
@@ -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>
index 1c9b220356b736dc7d025ec1c6f76ec617110fb0..632eacf5cc5f295914e1f8914faa66af15ab3557 100644 (file)
@@ -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:");
index b88143713db72bd04d4b10de833ebc9e4cf6d927..5a84f4564608079658a7d4fbbcf6dcdf72e1fc46 100644 (file)
 ==================================================================== */
 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.
diff --git a/src/testcases/org/apache/poi/hssf/data/45365.xls b/src/testcases/org/apache/poi/hssf/data/45365.xls
new file mode 100644 (file)
index 0000000..fbf1d97
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/45365.xls differ
index e52a3bc961af2b3a85adfb951496240b59f91c62..60f5d2ca72d7c227cbff61d48d21d7587526ffca 100644 (file)
@@ -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();