|
|
@@ -14,6 +14,7 @@ |
|
|
|
See the License for the specific language governing permissions and |
|
|
|
limitations under the License. |
|
|
|
==================================================================== */ |
|
|
|
|
|
|
|
package org.apache.poi.hssf.eventusermodel.examples; |
|
|
|
|
|
|
|
import java.io.FileInputStream; |
|
|
@@ -29,7 +30,7 @@ import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener; |
|
|
|
import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener; |
|
|
|
import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord; |
|
|
|
import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord; |
|
|
|
import org.apache.poi.hssf.model.FormulaParser; |
|
|
|
import org.apache.poi.hssf.model.HSSFFormulaParser; |
|
|
|
import org.apache.poi.hssf.record.BOFRecord; |
|
|
|
import org.apache.poi.hssf.record.BlankRecord; |
|
|
|
import org.apache.poi.hssf.record.BoolErrRecord; |
|
|
@@ -54,21 +55,21 @@ public class XLS2CSVmra implements HSSFListener { |
|
|
|
private int minColumns; |
|
|
|
private POIFSFileSystem fs; |
|
|
|
private PrintStream output; |
|
|
|
|
|
|
|
|
|
|
|
private int lastRowNumber; |
|
|
|
private int lastColumnNumber; |
|
|
|
|
|
|
|
|
|
|
|
/** Should we output the formula, or the value it has? */ |
|
|
|
private boolean outputFormulaValues = true; |
|
|
|
|
|
|
|
|
|
|
|
/** For parsing Formulas */ |
|
|
|
private SheetRecordCollectingListener workbookBuildingListener; |
|
|
|
private HSSFWorkbook stubWorkbook; |
|
|
|
|
|
|
|
|
|
|
|
// Records we pick up as we process |
|
|
|
private SSTRecord sstRecord; |
|
|
|
private FormatTrackingHSSFListener formatListener; |
|
|
|
|
|
|
|
|
|
|
|
// For handling formulas with string results |
|
|
|
private int nextRow; |
|
|
|
private int nextColumn; |
|
|
@@ -85,7 +86,7 @@ public class XLS2CSVmra implements HSSFListener { |
|
|
|
this.output = output; |
|
|
|
this.minColumns = minColumns; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Creates a new XLS -> CSV converter |
|
|
|
* @param filename The file to process |
|
|
@@ -99,38 +100,38 @@ public class XLS2CSVmra implements HSSFListener { |
|
|
|
System.out, minColumns |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Initiates the processing of the XLS file to CSV |
|
|
|
*/ |
|
|
|
public void process() throws IOException { |
|
|
|
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this); |
|
|
|
formatListener = new FormatTrackingHSSFListener(listener); |
|
|
|
|
|
|
|
formatListener = new FormatTrackingHSSFListener(listener); |
|
|
|
|
|
|
|
HSSFEventFactory factory = new HSSFEventFactory(); |
|
|
|
HSSFRequest request = new HSSFRequest(); |
|
|
|
|
|
|
|
|
|
|
|
if(outputFormulaValues) { |
|
|
|
request.addListenerForAllRecords(formatListener); |
|
|
|
} else { |
|
|
|
workbookBuildingListener = new SheetRecordCollectingListener(formatListener); |
|
|
|
request.addListenerForAllRecords(workbookBuildingListener); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
factory.processWorkbookEvents(request, fs); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Main HSSFListener method, processes events, and outputs the |
|
|
|
* CSV as the file is processed. |
|
|
|
* CSV as the file is processed. |
|
|
|
*/ |
|
|
|
public void processRecord(Record record) { |
|
|
|
int thisRow = -1; |
|
|
|
int thisColumn = -1; |
|
|
|
String thisStr = null; |
|
|
|
|
|
|
|
|
|
|
|
switch (record.getSid()) |
|
|
|
{ |
|
|
|
{ |
|
|
|
case BOFRecord.sid: |
|
|
|
BOFRecord br = (BOFRecord)record; |
|
|
|
if(br.getType() == BOFRecord.TYPE_WORKSHEET) { |
|
|
@@ -140,109 +141,109 @@ public class XLS2CSVmra implements HSSFListener { |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case SSTRecord.sid: |
|
|
|
sstRecord = (SSTRecord) record; |
|
|
|
break; |
|
|
|
|
|
|
|
case BlankRecord.sid: |
|
|
|
BlankRecord brec = (BlankRecord) record; |
|
|
|
|
|
|
|
thisRow = brec.getRow(); |
|
|
|
thisColumn = brec.getColumn(); |
|
|
|
thisStr = ""; |
|
|
|
break; |
|
|
|
case BoolErrRecord.sid: |
|
|
|
BoolErrRecord berec = (BoolErrRecord) record; |
|
|
|
|
|
|
|
thisRow = berec.getRow(); |
|
|
|
thisColumn = berec.getColumn(); |
|
|
|
thisStr = ""; |
|
|
|
break; |
|
|
|
|
|
|
|
case FormulaRecord.sid: |
|
|
|
FormulaRecord frec = (FormulaRecord) record; |
|
|
|
|
|
|
|
thisRow = frec.getRow(); |
|
|
|
thisColumn = frec.getColumn(); |
|
|
|
|
|
|
|
if(outputFormulaValues) { |
|
|
|
if(Double.isNaN( frec.getValue() )) { |
|
|
|
// Formula result is a string |
|
|
|
// This is stored in the next record |
|
|
|
outputNextStringRecord = true; |
|
|
|
nextRow = frec.getRow(); |
|
|
|
nextColumn = frec.getColumn(); |
|
|
|
} else { |
|
|
|
thisStr = formatListener.formatNumberDateCell(frec); |
|
|
|
} |
|
|
|
} else { |
|
|
|
thisStr = '"' + |
|
|
|
FormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()) + '"'; |
|
|
|
} |
|
|
|
break; |
|
|
|
case StringRecord.sid: |
|
|
|
if(outputNextStringRecord) { |
|
|
|
// String for formula |
|
|
|
StringRecord srec = (StringRecord)record; |
|
|
|
thisStr = srec.getString(); |
|
|
|
thisRow = nextRow; |
|
|
|
thisColumn = nextColumn; |
|
|
|
outputNextStringRecord = false; |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case LabelRecord.sid: |
|
|
|
LabelRecord lrec = (LabelRecord) record; |
|
|
|
|
|
|
|
thisRow = lrec.getRow(); |
|
|
|
thisColumn = lrec.getColumn(); |
|
|
|
thisStr = '"' + lrec.getValue() + '"'; |
|
|
|
break; |
|
|
|
case LabelSSTRecord.sid: |
|
|
|
LabelSSTRecord lsrec = (LabelSSTRecord) record; |
|
|
|
|
|
|
|
thisRow = lsrec.getRow(); |
|
|
|
thisColumn = lsrec.getColumn(); |
|
|
|
if(sstRecord == null) { |
|
|
|
thisStr = '"' + "(No SST Record, can't identify string)" + '"'; |
|
|
|
} else { |
|
|
|
thisStr = '"' + sstRecord.getString(lsrec.getSSTIndex()).toString() + '"'; |
|
|
|
} |
|
|
|
break; |
|
|
|
case NoteRecord.sid: |
|
|
|
NoteRecord nrec = (NoteRecord) record; |
|
|
|
|
|
|
|
thisRow = nrec.getRow(); |
|
|
|
thisColumn = nrec.getColumn(); |
|
|
|
// TODO: Find object to match nrec.getShapeId() |
|
|
|
thisStr = '"' + "(TODO)" + '"'; |
|
|
|
break; |
|
|
|
case NumberRecord.sid: |
|
|
|
NumberRecord numrec = (NumberRecord) record; |
|
|
|
|
|
|
|
thisRow = numrec.getRow(); |
|
|
|
thisColumn = numrec.getColumn(); |
|
|
|
|
|
|
|
// Format |
|
|
|
thisStr = formatListener.formatNumberDateCell(numrec); |
|
|
|
break; |
|
|
|
case RKRecord.sid: |
|
|
|
RKRecord rkrec = (RKRecord) record; |
|
|
|
|
|
|
|
thisRow = rkrec.getRow(); |
|
|
|
thisColumn = rkrec.getColumn(); |
|
|
|
thisStr = '"' + "(TODO)" + '"'; |
|
|
|
break; |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
case BlankRecord.sid: |
|
|
|
BlankRecord brec = (BlankRecord) record; |
|
|
|
|
|
|
|
thisRow = brec.getRow(); |
|
|
|
thisColumn = brec.getColumn(); |
|
|
|
thisStr = ""; |
|
|
|
break; |
|
|
|
case BoolErrRecord.sid: |
|
|
|
BoolErrRecord berec = (BoolErrRecord) record; |
|
|
|
|
|
|
|
thisRow = berec.getRow(); |
|
|
|
thisColumn = berec.getColumn(); |
|
|
|
thisStr = ""; |
|
|
|
break; |
|
|
|
|
|
|
|
case FormulaRecord.sid: |
|
|
|
FormulaRecord frec = (FormulaRecord) record; |
|
|
|
|
|
|
|
thisRow = frec.getRow(); |
|
|
|
thisColumn = frec.getColumn(); |
|
|
|
|
|
|
|
if(outputFormulaValues) { |
|
|
|
if(Double.isNaN( frec.getValue() )) { |
|
|
|
// Formula result is a string |
|
|
|
// This is stored in the next record |
|
|
|
outputNextStringRecord = true; |
|
|
|
nextRow = frec.getRow(); |
|
|
|
nextColumn = frec.getColumn(); |
|
|
|
} else { |
|
|
|
thisStr = formatListener.formatNumberDateCell(frec); |
|
|
|
} |
|
|
|
} else { |
|
|
|
thisStr = '"' + |
|
|
|
HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()) + '"'; |
|
|
|
} |
|
|
|
break; |
|
|
|
case StringRecord.sid: |
|
|
|
if(outputNextStringRecord) { |
|
|
|
// String for formula |
|
|
|
StringRecord srec = (StringRecord)record; |
|
|
|
thisStr = srec.getString(); |
|
|
|
thisRow = nextRow; |
|
|
|
thisColumn = nextColumn; |
|
|
|
outputNextStringRecord = false; |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case LabelRecord.sid: |
|
|
|
LabelRecord lrec = (LabelRecord) record; |
|
|
|
|
|
|
|
thisRow = lrec.getRow(); |
|
|
|
thisColumn = lrec.getColumn(); |
|
|
|
thisStr = '"' + lrec.getValue() + '"'; |
|
|
|
break; |
|
|
|
case LabelSSTRecord.sid: |
|
|
|
LabelSSTRecord lsrec = (LabelSSTRecord) record; |
|
|
|
|
|
|
|
thisRow = lsrec.getRow(); |
|
|
|
thisColumn = lsrec.getColumn(); |
|
|
|
if(sstRecord == null) { |
|
|
|
thisStr = '"' + "(No SST Record, can't identify string)" + '"'; |
|
|
|
} else { |
|
|
|
thisStr = '"' + sstRecord.getString(lsrec.getSSTIndex()).toString() + '"'; |
|
|
|
} |
|
|
|
break; |
|
|
|
case NoteRecord.sid: |
|
|
|
NoteRecord nrec = (NoteRecord) record; |
|
|
|
|
|
|
|
thisRow = nrec.getRow(); |
|
|
|
thisColumn = nrec.getColumn(); |
|
|
|
// TODO: Find object to match nrec.getShapeId() |
|
|
|
thisStr = '"' + "(TODO)" + '"'; |
|
|
|
break; |
|
|
|
case NumberRecord.sid: |
|
|
|
NumberRecord numrec = (NumberRecord) record; |
|
|
|
|
|
|
|
thisRow = numrec.getRow(); |
|
|
|
thisColumn = numrec.getColumn(); |
|
|
|
|
|
|
|
// Format |
|
|
|
thisStr = formatListener.formatNumberDateCell(numrec); |
|
|
|
break; |
|
|
|
case RKRecord.sid: |
|
|
|
RKRecord rkrec = (RKRecord) record; |
|
|
|
|
|
|
|
thisRow = rkrec.getRow(); |
|
|
|
thisColumn = rkrec.getColumn(); |
|
|
|
thisStr = '"' + "(TODO)" + '"'; |
|
|
|
break; |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
// Handle new row |
|
|
|
if(thisRow != -1 && thisRow != lastRowNumber) { |
|
|
|
lastColumnNumber = -1; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Handle missing column |
|
|
|
if(record instanceof MissingCellDummyRecord) { |
|
|
|
MissingCellDummyRecord mc = (MissingCellDummyRecord)record; |
|
|
@@ -250,7 +251,7 @@ public class XLS2CSVmra implements HSSFListener { |
|
|
|
thisColumn = mc.getColumn(); |
|
|
|
thisStr = ""; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// If we got something to print out, do so |
|
|
|
if(thisStr != null) { |
|
|
|
if(thisColumn > 0) { |
|
|
@@ -258,13 +259,13 @@ public class XLS2CSVmra implements HSSFListener { |
|
|
|
} |
|
|
|
output.print(thisStr); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Update column and row count |
|
|
|
if(thisRow > -1) |
|
|
|
lastRowNumber = thisRow; |
|
|
|
if(thisColumn > -1) |
|
|
|
lastColumnNumber = thisColumn; |
|
|
|
|
|
|
|
|
|
|
|
// Handle end of row |
|
|
|
if(record instanceof LastCellOfRowDummyRecord) { |
|
|
|
// Print out any missing commas if needed |
|
|
@@ -275,27 +276,27 @@ public class XLS2CSVmra implements HSSFListener { |
|
|
|
output.print(','); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// We're onto a new row |
|
|
|
lastColumnNumber = -1; |
|
|
|
|
|
|
|
|
|
|
|
// End the row |
|
|
|
output.println(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) throws Exception { |
|
|
|
if(args.length < 1) { |
|
|
|
System.err.println("Use:"); |
|
|
|
System.err.println(" XLS2CSVmra <xls file> [min columns]"); |
|
|
|
System.exit(1); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int minColumns = -1; |
|
|
|
if(args.length >= 2) { |
|
|
|
minColumns = Integer.parseInt(args[1]); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
XLS2CSVmra xls2csv = new XLS2CSVmra(args[0], minColumns); |
|
|
|
xls2csv.process(); |
|
|
|
} |