Implement a proxy HSSFListener which tracks the format records, and lets you lookup the format string for a given cell. Convert the xls to csv example to use it
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@646405 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
3a7871a2dd
commit
63409a6647
@ -0,0 +1,117 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
package org.apache.poi.hssf.eventusermodel;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
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.Record;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A proxy HSSFListener that keeps track of the document
|
||||||
|
* formatting records, and provides an easy way to look
|
||||||
|
* up the format strings used by cells from their ids.
|
||||||
|
*/
|
||||||
|
public class FormatTrackingHSSFListener implements HSSFListener {
|
||||||
|
private HSSFListener childListener;
|
||||||
|
private Map customFormatRecords = new Hashtable();
|
||||||
|
private List xfRecords = new ArrayList();
|
||||||
|
|
||||||
|
public FormatTrackingHSSFListener(HSSFListener childListener) {
|
||||||
|
this.childListener = childListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process this record ourselves, and then
|
||||||
|
* pass it on to our child listener
|
||||||
|
*/
|
||||||
|
public void processRecord(Record record) {
|
||||||
|
// Handle it ourselves
|
||||||
|
processRecordInternally(record);
|
||||||
|
|
||||||
|
// Now pass on to our child
|
||||||
|
childListener.processRecord(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the record ourselves, but do not
|
||||||
|
* pass it on to the child Listener.
|
||||||
|
* @param record
|
||||||
|
*/
|
||||||
|
public void processRecordInternally(Record record) {
|
||||||
|
if(record instanceof FormatRecord) {
|
||||||
|
FormatRecord fr = (FormatRecord) record;
|
||||||
|
customFormatRecords.put(new Integer(fr.getIndexCode()), fr);
|
||||||
|
}
|
||||||
|
if(record instanceof ExtendedFormatRecord) {
|
||||||
|
ExtendedFormatRecord xr = (ExtendedFormatRecord) record;
|
||||||
|
xfRecords.add(xr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the format string, eg $##.##, for the
|
||||||
|
* given number format index.
|
||||||
|
*/
|
||||||
|
public String getFormatString(int formatIndex) {
|
||||||
|
String format = null;
|
||||||
|
if(formatIndex >= HSSFDataFormat.getNumberOfBuiltinBuiltinFormats()) {
|
||||||
|
FormatRecord tfr = (FormatRecord)customFormatRecords.get(new Integer(formatIndex));
|
||||||
|
if(tfr == null) {
|
||||||
|
System.err.println("Requested format at index " + formatIndex + ", but it wasn't found");
|
||||||
|
} else {
|
||||||
|
format = tfr.getFormatString();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
format = HSSFDataFormat.getBuiltinFormat((short)formatIndex);
|
||||||
|
}
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the format string, eg $##.##, used
|
||||||
|
* by your cell
|
||||||
|
*/
|
||||||
|
public String getFormatString(CellValueRecordInterface cell) {
|
||||||
|
int formatIndex = getFormatIndex(cell);
|
||||||
|
if(formatIndex == -1) {
|
||||||
|
// Not found
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getFormatString(formatIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the format string, used by your cell,
|
||||||
|
* or -1 if none found
|
||||||
|
*/
|
||||||
|
public int getFormatIndex(CellValueRecordInterface cell) {
|
||||||
|
ExtendedFormatRecord xfr = (ExtendedFormatRecord)
|
||||||
|
xfRecords.get(cell.getXFIndex());
|
||||||
|
if(xfr == null) {
|
||||||
|
System.err.println("Cell " + cell.getRow() + "," + cell.getColumn() + " uses XF with index " + cell.getXFIndex() + ", but we don't have that");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return xfr.getFormatIndex();
|
||||||
|
}
|
||||||
|
}
|
@ -29,6 +29,7 @@ import java.util.Hashtable;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
|
||||||
import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
|
import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
|
||||||
import org.apache.poi.hssf.eventusermodel.HSSFListener;
|
import org.apache.poi.hssf.eventusermodel.HSSFListener;
|
||||||
import org.apache.poi.hssf.eventusermodel.HSSFRequest;
|
import org.apache.poi.hssf.eventusermodel.HSSFRequest;
|
||||||
@ -70,8 +71,7 @@ public class XLS2CSVmra implements HSSFListener {
|
|||||||
|
|
||||||
// Records we pick up as we process
|
// Records we pick up as we process
|
||||||
private SSTRecord sstRecord;
|
private SSTRecord sstRecord;
|
||||||
private Map customFormatRecords = new Hashtable();
|
private FormatTrackingHSSFListener formatListener;
|
||||||
private List xfRecords = new ArrayList();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new XLS -> CSV converter
|
* Creates a new XLS -> CSV converter
|
||||||
@ -104,9 +104,11 @@ public class XLS2CSVmra implements HSSFListener {
|
|||||||
*/
|
*/
|
||||||
public void process() throws IOException {
|
public void process() throws IOException {
|
||||||
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
|
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
|
||||||
|
formatListener = new FormatTrackingHSSFListener(listener);
|
||||||
|
|
||||||
HSSFEventFactory factory = new HSSFEventFactory();
|
HSSFEventFactory factory = new HSSFEventFactory();
|
||||||
HSSFRequest request = new HSSFRequest();
|
HSSFRequest request = new HSSFRequest();
|
||||||
request.addListenerForAllRecords(listener);
|
request.addListenerForAllRecords(formatListener);
|
||||||
|
|
||||||
factory.processWorkbookEvents(request, fs);
|
factory.processWorkbookEvents(request, fs);
|
||||||
}
|
}
|
||||||
@ -125,14 +127,6 @@ public class XLS2CSVmra implements HSSFListener {
|
|||||||
case SSTRecord.sid:
|
case SSTRecord.sid:
|
||||||
sstRecord = (SSTRecord) record;
|
sstRecord = (SSTRecord) record;
|
||||||
break;
|
break;
|
||||||
case FormatRecord.sid:
|
|
||||||
FormatRecord fr = (FormatRecord) record;
|
|
||||||
customFormatRecords.put(new Integer(fr.getIndexCode()), fr);
|
|
||||||
break;
|
|
||||||
case ExtendedFormatRecord.sid:
|
|
||||||
ExtendedFormatRecord xr = (ExtendedFormatRecord) record;
|
|
||||||
xfRecords.add(xr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BlankRecord.sid:
|
case BlankRecord.sid:
|
||||||
BlankRecord brec = (BlankRecord) record;
|
BlankRecord brec = (BlankRecord) record;
|
||||||
@ -259,41 +253,32 @@ public class XLS2CSVmra implements HSSFListener {
|
|||||||
*/
|
*/
|
||||||
private String formatNumberDateCell(CellValueRecordInterface cell, double value) {
|
private String formatNumberDateCell(CellValueRecordInterface cell, double value) {
|
||||||
// Get the built in format, if there is one
|
// Get the built in format, if there is one
|
||||||
ExtendedFormatRecord xfr = (ExtendedFormatRecord)
|
int formatIndex = formatListener.getFormatIndex(cell);
|
||||||
xfRecords.get(cell.getXFIndex());
|
String formatString = formatListener.getFormatString(cell);
|
||||||
if(xfr == null) {
|
|
||||||
System.err.println("Cell " + cell.getRow() + "," + cell.getColumn() + " uses XF with index " + cell.getXFIndex() + ", but we don't have that");
|
if(formatString == null) {
|
||||||
return Double.toString(value);
|
return Double.toString(value);
|
||||||
} else {
|
} else {
|
||||||
int formatIndex = xfr.getFormatIndex();
|
|
||||||
String format;
|
|
||||||
if(formatIndex >= HSSFDataFormat.getNumberOfBuiltinBuiltinFormats()) {
|
|
||||||
FormatRecord tfr = (FormatRecord)customFormatRecords.get(new Integer(formatIndex));
|
|
||||||
format = tfr.getFormatString();
|
|
||||||
} else {
|
|
||||||
format = HSSFDataFormat.getBuiltinFormat(xfr.getFormatIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is it a date?
|
// Is it a date?
|
||||||
if(HSSFDateUtil.isADateFormat(formatIndex,format) &&
|
if(HSSFDateUtil.isADateFormat(formatIndex,formatString) &&
|
||||||
HSSFDateUtil.isValidExcelDate(value)) {
|
HSSFDateUtil.isValidExcelDate(value)) {
|
||||||
// Java wants M not m for month
|
// Java wants M not m for month
|
||||||
format = format.replace('m','M');
|
formatString = formatString.replace('m','M');
|
||||||
// Change \- into -, if it's there
|
// Change \- into -, if it's there
|
||||||
format = format.replaceAll("\\\\-","-");
|
formatString = formatString.replaceAll("\\\\-","-");
|
||||||
|
|
||||||
// Format as a date
|
// Format as a date
|
||||||
Date d = HSSFDateUtil.getJavaDate(value, false);
|
Date d = HSSFDateUtil.getJavaDate(value, false);
|
||||||
DateFormat df = new SimpleDateFormat(format);
|
DateFormat df = new SimpleDateFormat(formatString);
|
||||||
return df.format(d);
|
return df.format(d);
|
||||||
} else {
|
} else {
|
||||||
if(format == "General") {
|
if(formatString == "General") {
|
||||||
// Some sort of wierd default
|
// Some sort of wierd default
|
||||||
return Double.toString(value);
|
return Double.toString(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format as a number
|
// Format as a number
|
||||||
DecimalFormat df = new DecimalFormat(format);
|
DecimalFormat df = new DecimalFormat(formatString);
|
||||||
return df.format(value);
|
return df.format(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
|
||||||
|
package org.apache.poi.hssf.eventusermodel;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||||
|
import org.apache.poi.hssf.record.Record;
|
||||||
|
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||||
|
/**
|
||||||
|
* Tests for FormatTrackingHSSFListener
|
||||||
|
*/
|
||||||
|
public final class TestFormatTrackingHSSFListener extends TestCase {
|
||||||
|
private FormatTrackingHSSFListener listener;
|
||||||
|
|
||||||
|
public void setUp() {
|
||||||
|
HSSFRequest req = new HSSFRequest();
|
||||||
|
MockHSSFListener mockListen = new MockHSSFListener();
|
||||||
|
listener = new FormatTrackingHSSFListener(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFormats() throws Exception {
|
||||||
|
assertEquals("_(*#,##0_);_(*(#,##0);_(* \"-\"_);_(@_)", listener.getFormatString(41));
|
||||||
|
assertEquals("_($*#,##0_);_($*(#,##0);_($* \"-\"_);_(@_)", listener.getFormatString(42));
|
||||||
|
assertEquals("_(*#,##0.00_);_(*(#,##0.00);_(*\"-\"??_);_(@_)", listener.getFormatString(43));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class MockHSSFListener implements HSSFListener {
|
||||||
|
public MockHSSFListener() {}
|
||||||
|
private final List _records = new ArrayList();
|
||||||
|
|
||||||
|
public void processRecord(Record record) {
|
||||||
|
_records.add(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user