I want to clone an Excel sheet and all of its contents. I tried the XSSFWorkbook cloneSheet method, but it seems the workbook is corrupted if my sheet contains an Excel table. See the examle workbook below with a simple table:
When I try to open the output workbook, I get a prompt telling me that the file is broken and needs to be repaired. If I recover the workbook, it is clear the table has not been copied correctly; the original totals row is now a data row.
try (InputStream is = Table.class.getResourceAsStream("table.xlsx")) {
XSSFWorkbook workbook = new XSSFWorkbook(is);
workbook.cloneSheet(0, "Test");
try (OutputStream fileOut = new FileOutputStream("table-2.xlsx")) {
workbook.write(fileOut);
}
} catch (IOException e) {
e.printStackTrace();
}
How I would go about copying this sheet? Any help is appreciated!
XSSFWorkbook.cloneSheet clones a sheet. But it does not considering the possible defined tables in it. It simply clones the table references. But two table-ranges in sheets cannot refer to the same table reference. The tables itself needs to be cloned. That's why the corrupted workbook as result.
I've tried to solve this by programming a method cloneTables(XSSFSheet sheet) which simply creates clones of each table in a sheet which then refer to their own table reference each. I consider table styles, auto-filter, a totals-row and calculated column formulas. I hope I have not overlooked something, but I doubt that.
The code its tested and works using current apache poi 5.2.2.
It contains fixes for following bugs too:
XSSFTable.updateHeaders fails in Excel workbooks created using current Excel versions. This is because of the test row.getCTRow().validate() which always will be false because of the usage of new name spaces. See Renaming headers of XSSFTable with Apache Poi leads to corrupt XLSX-file.
XSSFSheet.removeTable does not remove the links to the table part reference from the sheet.
Complete example to test:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.ss.SpreadsheetVersion;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn;
class ExcelCloneSheetHavingTable {
static void updateHeaders(XSSFTable table) {
XSSFSheet sheet = (XSSFSheet)table.getParent();
CellReference ref = table.getStartCellReference();
if (ref == null) return;
int headerRow = ref.getRow();
int firstHeaderColumn = ref.getCol();
XSSFRow row = sheet.getRow(headerRow);
DataFormatter formatter = new DataFormatter();
if (row != null /*&& row.getCTRow().validate()*/) { // see bug: https://stackoverflow.com/questions/55532006/renaming-headers-of-xssftable-with-apache-poi-leads-to-corrupt-xlsx-file/55539181#55539181
int cellnum = firstHeaderColumn;
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumns ctTableColumns = table.getCTTable().getTableColumns();
if(ctTableColumns != null) {
for (org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn col : ctTableColumns.getTableColumnList()) {
XSSFCell cell = row.getCell(cellnum);
if (cell != null) {
String colName = formatter.formatCellValue(cell);
colName = colName.replace("\n", "_x000a_");
colName = colName.replace("\r", "_x000d_");
col.setName(colName);
}
cellnum++;
}
}
}
//tableColumns = null;
//columnMap = null;
//xmlColumnPrs = null;
//commonXPath = null;
try {
java.lang.reflect.Field tableColumns = XSSFTable.class.getDeclaredField("tableColumns");
tableColumns.setAccessible(true);
tableColumns.set(table, null);
java.lang.reflect.Field columnMap = XSSFTable.class.getDeclaredField("columnMap");
columnMap.setAccessible(true);
columnMap.set(table, null);
java.lang.reflect.Field xmlColumnPrs = XSSFTable.class.getDeclaredField("xmlColumnPrs");
xmlColumnPrs.setAccessible(true);
xmlColumnPrs.set(table, null);
java.lang.reflect.Field commonXPath = XSSFTable.class.getDeclaredField("commonXPath");
commonXPath.setAccessible(true);
commonXPath.set(table, null);
} catch (Exception ex) {
ex.printStackTrace();
}
}
static String getSubtotalFormulaStartFromTotalsRowFunction(int intTotalsRowFunction) {
final int INT_NONE = 1;
final int INT_SUM = 2;
final int INT_MIN = 3;
final int INT_MAX = 4;
final int INT_AVERAGE = 5;
final int INT_COUNT = 6;
final int INT_COUNT_NUMS = 7;
final int INT_STD_DEV = 8;
final int INT_VAR = 9;
final int INT_CUSTOM = 10;
String subtotalFormulaStart = null;
switch (intTotalsRowFunction) {
case INT_NONE:
subtotalFormulaStart = null;
break;
case INT_SUM:
subtotalFormulaStart = "SUBTOTAL(109";
break;
case INT_MIN:
subtotalFormulaStart = "SUBTOTAL(105";
break;
case INT_MAX:
subtotalFormulaStart = "SUBTOTAL(104";
break;
case INT_AVERAGE:
subtotalFormulaStart = "SUBTOTAL(101";
break;
case INT_COUNT:
subtotalFormulaStart = "SUBTOTAL(103";
break;
case INT_COUNT_NUMS:
subtotalFormulaStart = "SUBTOTAL(102";
break;
case INT_STD_DEV:
subtotalFormulaStart = "SUBTOTAL(107";
break;
case INT_VAR:
subtotalFormulaStart = "SUBTOTAL(110";
break;
case INT_CUSTOM:
subtotalFormulaStart = null;
break;
default:
subtotalFormulaStart = null;
}
return subtotalFormulaStart;
}
static void cloneTables(XSSFSheet sheet) {
for (XSSFTable table : sheet.getTables()) {
// clone table; XSSFTable.setArea fails and throws exception for too small tables
XSSFTable clonedTable = null;
int rowCount = (table.getArea().getLastCell().getRow() - table.getArea().getFirstCell().getRow()) + 1;
int headerRowCount = table.getHeaderRowCount(); if (headerRowCount == 0) headerRowCount = 1;
int minimumRowCount = 1 + headerRowCount + table.getTotalsRowCount();
if (rowCount >= minimumRowCount) {
clonedTable = sheet.createTable(table.getArea());
}
if (clonedTable != null) {
//clonedTable.updateHeaders(); // don't work, see bug: https://stackoverflow.com/questions/55532006/renaming-headers-of-xssftable-with-apache-poi-leads-to-corrupt-xlsx-file/55539181#55539181
updateHeaders(clonedTable);
// clone style
clonedTable.setStyleName(table.getStyleName());
XSSFTableStyleInfo style = (XSSFTableStyleInfo)table.getStyle();
XSSFTableStyleInfo clonedStyle = (XSSFTableStyleInfo)clonedTable.getStyle();
if (style != null && clonedStyle != null) {
clonedStyle.setShowColumnStripes(style.isShowColumnStripes());
clonedStyle.setShowRowStripes(style.isShowRowStripes());
clonedStyle.setFirstColumn(style.isShowFirstColumn());
clonedStyle.setLastColumn(style.isShowLastColumn());
}
//clone autofilter
clonedTable.getCTTable().setAutoFilter(table.getCTTable().getAutoFilter());
//clone totalsrow
int totalsRowCount = table.getTotalsRowCount();
if (totalsRowCount == 1) { // never seen more than one totals row
XSSFRow totalsRow = sheet.getRow(clonedTable.getEndCellReference().getRow());
if (clonedTable.getCTTable().getTableColumns().getTableColumnList().size() > 0) {
clonedTable.getCTTable().setTotalsRowCount(totalsRowCount);
for (int i = 0; i < clonedTable.getCTTable().getTableColumns().getTableColumnList().size(); i++) {
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn tableCol = table.getCTTable().getTableColumns().getTableColumnList().get(i);
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn clonedTableCol = clonedTable.getCTTable().getTableColumns().getTableColumnList().get(i);
clonedTableCol.setTotalsRowFunction(tableCol.getTotalsRowFunction());
int intTotalsRowFunction = clonedTableCol.getTotalsRowFunction().intValue();
sheet.getWorkbook().setCellFormulaValidation(false);
if (intTotalsRowFunction == 10) { //custom
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableFormula totalsRowFormula = tableCol.getTotalsRowFormula();
clonedTableCol.setTotalsRowFormula(totalsRowFormula);
totalsRow.getCell(clonedTable.getStartCellReference().getCol()+i).setCellFormula(totalsRowFormula.getStringValue());
} else if (intTotalsRowFunction == 1) { //none
//totalsRow.getCell(clonedTable.getStartCellReference().getCol()+i).setBlank();
} else {
String subtotalFormulaStart = getSubtotalFormulaStartFromTotalsRowFunction(intTotalsRowFunction);
if (subtotalFormulaStart != null)
totalsRow.getCell(clonedTable.getStartCellReference().getCol()+i).setCellFormula(subtotalFormulaStart + "," + clonedTable.getName() +"[" + clonedTableCol.getName()+ "])");
}
}
}
}
// clone calculated column formulas
if (clonedTable.getCTTable().getTableColumns().getTableColumnList().size() > 0) {
clonedTable.getCTTable().setTotalsRowCount(totalsRowCount);
for (int i = 0; i < clonedTable.getCTTable().getTableColumns().getTableColumnList().size(); i++) {
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn tableCol = table.getCTTable().getTableColumns().getTableColumnList().get(i);
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn clonedTableCol = clonedTable.getCTTable().getTableColumns().getTableColumnList().get(i);
if (tableCol.getCalculatedColumnFormula() != null) {
clonedTableCol.setCalculatedColumnFormula(tableCol.getCalculatedColumnFormula());
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableFormula calculatedColumnFormula = clonedTableCol.getCalculatedColumnFormula();
String formula = tableCol.getCalculatedColumnFormula().getStringValue();
String clonedFormula = formula.replace(table.getName(), clonedTable.getName());
calculatedColumnFormula.setStringValue(clonedFormula);
int rFirst = clonedTable.getStartCellReference().getRow() + clonedTable.getHeaderRowCount();
int rLast = clonedTable.getEndCellReference().getRow() - clonedTable.getTotalsRowCount();
int c = clonedTable.getStartCellReference().getCol() + i;
sheet.getWorkbook().setCellFormulaValidation(false);
for (int r = rFirst; r <= rLast; r++) {
XSSFRow row = sheet.getRow(r); if (row == null) row = sheet.createRow(r);
XSSFCell cell = row.getCell(c); if (cell == null) cell = row.createCell(c);
cell.setCellFormula(clonedFormula);
}
}
}
}
}
// remove old table; do that even if XSSFsheet.createTable failed, because a one-cell-table doesn't make any sense
String rId = sheet.getRelationId(table);
sheet.removeTable(table);
// remove links to the table part reference
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableParts tblParts = sheet.getCTWorksheet().getTableParts();
if (tblParts != null && tblParts.getTablePartList().size() > 0) {
for (int i = 0; i < tblParts.getTablePartList().size(); i++) {
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTablePart tblPart = tblParts.getTablePartArray​(i);
if(tblPart.getId().equals(rId)) {
tblParts.removeTablePart​(i);
}
}
}
}
}
public static void main(String[] args) throws Exception {
try (Workbook workbook = WorkbookFactory.create(new FileInputStream("SAMPLE.xlsx"));
FileOutputStream out = new FileOutputStream("SAMPLE_NEW.xlsx")) {
XSSFSheet sheet = ((XSSFWorkbook)workbook).cloneSheet(0, "Test");
cloneTables(sheet);
workbook.write(out);
}
}
}
This code needs the full jar of all of the schemas, which is poi-ooxml-full-5.2.2.jar for apache poi 5.2.2, as mentioned in FAQ. Note, since apache poi 5.* the formerly used ooxml-schemas-*.jar cannot be used anymore. There must not be any ooxml-schemas-*.jar in class path when using apache poi 5.*.
Note, you need this additional. The file names poi-ooxml-5.2.2.jar and poi-ooxml-lite-5.2.2.jar respective poi-ooxml-full-5.2.2.jar are misleading. The *-lite*.jar respective *-full*.jar do not replace, but complement the poi-ooxml-5.2.2.jar.
Is there a way to not read the entire Excel documents row, I'm reading the cell's defined in the document, but, it's pulling in the entire sheet's columns???
I'm converting an Excel document to a CSV document. I am getting this result.
Aircraft ID (FADEC_SHIP_POS),Fleet (Fleet Name),Fault Date (TIMESTAMP or FADEC_DATE_TIME),Fault ID (FADEC_ID),Fault Description (FADEC_FAULT_DESCRIPTION),Priority (FADEC_PRIORITY),ATA,Flight Phase (FM),Report Type (REPORT_TYPE),Flight Number (FLT),Origin (ORIG),Destination (DEST),Site Reference Name,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
I don't need all those extra undefined columns, (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,)
also, there can be empty values in the row's defined columns: - these are expected and needed
6808-1,B757,2019-09-25 20:50:18,351-21A,P(S) 351-21,3,,Climb,901,1278,,,Sprint Airlines
my class
public class XlsxToCsv implements Processor {
private Logger log = Logger.getLogger(XlsxToCsv.class.getName());
private static final String CSV_SEPERATOR_CHAR=",";
private static final String NEW_LINE_CHARACTER="\r\n";
#Override
public void process(Exchange exchange) throws Exception {
log.info("Entering XLSX Excel to CSV ...");
int sheetIdx = 0;
byte[] in = exchange.getIn().getBody(byte[].class);
String out = excelToCSV(in,sheetIdx);
exchange.getIn().setBody(out);
log.info("Exiting XLSX Excel to CSV ...");
}
private String excelToCSV(byte[] xlsxFile, int sheetIdx) throws Exception {
InputStream is = null;
StringBuffer sb = new StringBuffer();
String cellVal = "";
try {
is = new ByteArrayInputStream(xlsxFile);
} catch (Exception e) {
e.printStackTrace();
}
XSSFWorkbook workBook = new XSSFWorkbook(is);
XSSFSheet workSheet = workBook.getSheetAt(sheetIdx);
for (int i = 0; i < workSheet.getPhysicalNumberOfRows(); i++) {
XSSFRow row = workSheet.getRow(i);
for (int j = 0; j < row.getPhysicalNumberOfCells(); j++) {
cellVal = getCellValueAsString(workBook, row.getCell(j));
if ( j == row.getPhysicalNumberOfCells() - 1) {
sb.append(cellVal).append(NEW_LINE_CHARACTER);
} else {
sb.append(cellVal).append(CSV_SEPERATOR_CHAR);
}
}
}
workBook.close();
return sb.toString();
}
private String getCellValueAsString(XSSFWorkbook workbook, XSSFCell cell) {
String cellValue = "";
if (cell != null) {
CellType cellType = cell.getCellType();
if (cellType == CellType.FORMULA) {
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
cellType = evaluator.evaluateFormulaCell(cell);
}
switch (cellType) {
case STRING:
cellValue = cell.getStringCellValue();
break;
case NUMERIC:
Double doubleValue = cell.getNumericCellValue();
int intValue = doubleValue.intValue();
cellValue = Integer.toString(intValue);
break;
case BOOLEAN:
cellValue = Boolean.toString(cell.getBooleanCellValue());
break;
case ERROR:
cellValue = cell.getErrorCellString();
break;
case BLANK:
break;
default:
break;
}
}
return cellValue;
}
}
It turns out that the template I'm using had spaces entered in the last elements in the spreadsheet, I removed and cleaned up the xlsx template and it is working as expected.
always learning, I wouldn't expect that, but, it is what it is,
Is there a way to update formula references when copying a formula in Apache POI?
Say in Excel you have in row 1 the formula =A1/B1. If you copy-paste it, say in row 5, the formula becomes =A5/B5.
In Apache POI if you run the lines
r5.getCell(2).setCellType(CellType.FORMULA);
r5.getCell(2).setCellFormula(r1.getCell(2).getCellFormula());
the formula remains =A1/B1.
Your code is not copy/pasting something but gets the formula string from one cell and sets exactly this formula string to another cell. This will not changing the formula string. How even should it do?
So the need is to get the the formula string from one cell and then adjust this formula string to the target cell.
Since apache poi is able to evaluate formulas, it must also be able to parse formulas. The parsing classes are in the packages org.apache.poi.ss.formula and org.apache.poi.ss.formula.ptg.
So we can use those classes to adjust the formula string to the target cell.
Example:
Following Excel workbook:
and following code:
import java.io.FileInputStream;
import org.apache.poi.ss.formula.*;
import org.apache.poi.ss.formula.ptg.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.util.CellAddress;
public class ExcelCopyFormula {
private static String copyFormula(XSSFSheet sheet, String formula, int coldiff, int rowdiff) {
XSSFEvaluationWorkbook workbookWrapper =
XSSFEvaluationWorkbook.create((XSSFWorkbook) sheet.getWorkbook());
Ptg[] ptgs = FormulaParser.parse(formula, workbookWrapper, FormulaType.CELL
, sheet.getWorkbook().getSheetIndex(sheet));
for (int i = 0; i < ptgs.length; i++) {
if (ptgs[i] instanceof RefPtgBase) { // base class for cell references
RefPtgBase ref = (RefPtgBase) ptgs[i];
if (ref.isColRelative())
ref.setColumn(ref.getColumn() + coldiff);
if (ref.isRowRelative())
ref.setRow(ref.getRow() + rowdiff);
}
else if (ptgs[i] instanceof AreaPtgBase) { // base class for range references
AreaPtgBase ref = (AreaPtgBase) ptgs[i];
if (ref.isFirstColRelative())
ref.setFirstColumn(ref.getFirstColumn() + coldiff);
if (ref.isLastColRelative())
ref.setLastColumn(ref.getLastColumn() + coldiff);
if (ref.isFirstRowRelative())
ref.setFirstRow(ref.getFirstRow() + rowdiff);
if (ref.isLastRowRelative())
ref.setLastRow(ref.getLastRow() + rowdiff);
}
}
formula = FormulaRenderer.toFormulaString(workbookWrapper, ptgs);
return formula;
}
public static void main(String[] args) throws Exception {
XSSFWorkbook workbook = (XSSFWorkbook)WorkbookFactory.create(new FileInputStream("test.xlsx"));
XSSFSheet sheet = workbook.getSheetAt(0);
for (Row row : sheet) {
for (Cell cell : row) {
//if (cell.getCellTypeEnum() == CellType.FORMULA) { // up to apache poi version 3
if (cell.getCellType() == CellType.FORMULA) { // since apache poi version 4
CellAddress source = cell.getAddress();
String formula = cell.getCellFormula();
System.out.print(source + "=" + formula);
int rowdiff = 3;
int coldiff = -2;
CellAddress target = new CellAddress(source.getRow() + rowdiff, source.getColumn() + coldiff);
String newformula = copyFormula(sheet, formula, coldiff, rowdiff);
System.out.println("->" + target + "=" + newformula);
}
}
}
workbook.close();
}
}
leads to following output:
E3=C3/D3->C6=A6/B6
E4=$C4/D$4->C7=$C7/B$4
E5=SUM(C3:D5)->C8=SUM(A6:B8)
E6=SUM(C$3:$D6)->C9=SUM(A$3:$D9)
E7=C3+SUM(C3:D7)->C10=A6+SUM(A6:B10)
E8=C$3+SUM($C3:D$8)->C11=A$3+SUM($C6:B$8)
Updated String copyFormula(Sheet sheet, String formula, int coldiff, int rowdiff) method which works for SS that is for HSSFas well as for XSSF:
private static String copyFormula(Sheet sheet, String formula, int coldiff, int rowdiff) {
Workbook workbook = sheet.getWorkbook();
EvaluationWorkbook evaluationWorkbook = null;
if (workbook instanceof HSSFWorkbook) {
evaluationWorkbook = HSSFEvaluationWorkbook.create((HSSFWorkbook) workbook);
} else if (workbook instanceof XSSFWorkbook) {
evaluationWorkbook = XSSFEvaluationWorkbook.create((XSSFWorkbook) workbook);
}
Ptg[] ptgs = FormulaParser.parse(formula, (FormulaParsingWorkbook)evaluationWorkbook,
FormulaType.CELL, sheet.getWorkbook().getSheetIndex(sheet));
for (int i = 0; i < ptgs.length; i++) {
if (ptgs[i] instanceof RefPtgBase) { // base class for cell references
RefPtgBase ref = (RefPtgBase) ptgs[i];
if (ref.isColRelative())
ref.setColumn(ref.getColumn() + coldiff);
if (ref.isRowRelative())
ref.setRow(ref.getRow() + rowdiff);
}
else if (ptgs[i] instanceof AreaPtgBase) { // base class for range references
AreaPtgBase ref = (AreaPtgBase) ptgs[i];
if (ref.isFirstColRelative())
ref.setFirstColumn(ref.getFirstColumn() + coldiff);
if (ref.isLastColRelative())
ref.setLastColumn(ref.getLastColumn() + coldiff);
if (ref.isFirstRowRelative())
ref.setFirstRow(ref.getFirstRow() + rowdiff);
if (ref.isLastRowRelative())
ref.setLastRow(ref.getLastRow() + rowdiff);
}
}
formula = FormulaRenderer.toFormulaString((FormulaRenderingWorkbook)evaluationWorkbook, ptgs);
return formula;
}
Just if you want the answer for the NPOI, I have created the C# version from the #AxelRichter updated answer:
public static string CopyFormula(ISheet sheet, string formula, int coldiff, int rowdiff)
{
var workbook = sheet.Workbook;
IFormulaParsingWorkbook evaluationWorkbook = null;
if (sheet is XSSFWorkbook)
{
evaluationWorkbook = XSSFEvaluationWorkbook.Create(workbook);
}
else if (sheet is HSSFWorkbook)
{
evaluationWorkbook = HSSFEvaluationWorkbook.Create(workbook);
}
else if (sheet is SXSSFWorkbook)
{
evaluationWorkbook = SXSSFEvaluationWorkbook.Create((SXSSFWorkbook)workbook);
}
var ptgs = FormulaParser.Parse(formula, evaluationWorkbook,FormulaType.Cell, sheet.Workbook.GetSheetIndex(sheet));
for (int i = 0; i < ptgs.Length; i++)
{
if (ptgs[i] is RefPtgBase) {
RefPtgBase ref2 = (RefPtgBase)ptgs[i];
if (ref2.IsColRelative)
ref2.Column = ref2.Column + coldiff;
if (ref2.IsRowRelative)
ref2.Row = ref2.Row + rowdiff;
}
else if (ptgs[i] is AreaPtgBase) {
AreaPtgBase ref2 = (AreaPtgBase)ptgs[i];
if (ref2.IsFirstColRelative)
ref2.FirstColumn += coldiff;
if (ref2.IsLastColRelative)
ref2.LastColumn += coldiff;
if (ref2.IsFirstRowRelative)
ref2.FirstRow += rowdiff;
if (ref2.IsLastRowRelative)
ref2.LastRow += rowdiff;
}
}
formula = FormulaRenderer.ToFormulaString((IFormulaRenderingWorkbook)evaluationWorkbook, ptgs);
return formula;
}
I need help to remove empty row between created list of records. i already code to remove empty rows however it able removed the first empty row only. here is the code i done:
private static void writeExcelFile(String[] keyValue, String fileName, String contents,
ArrayList<String> listProperties, ArrayList<String> listPropertiesDescription,
ArrayList<String> listPropertiesFileName) {
int rownum = 2;
HSSFSheet firstSheet;
HSSFWorkbook workbook = null;
workbook = new HSSFWorkbook();
firstSheet = workbook.createSheet("Resourcebundle");
Row headerRow = firstSheet.createRow((short) 1);
headerRow.setHeightInPoints(30);
headerRow.createCell((short) 0).setCellValue("Properties Name");
headerRow.createCell((short) 1).setCellValue("Properties Description");
headerRow.createCell((short) 2).setCellValue("Properties File Name");
System.out.println("listPropertiesDescription :: " + listPropertiesDescription.size());
System.out.println("listPropertiesFileName :: " + listPropertiesFileName.size());
System.out.println("listProperties all list :: " + listProperties.toString());
System.out.println("listPropertiesDescription all list :: "
+ listPropertiesDescription.toString());
int indexProperties = 0;
for (int i = rownum; i < listProperties.size(); i++) {
// Row row = firstSheet.getRow(i + 1);
Row row = firstSheet.getRow(i);
// System.out.println("row :: " + row);
if (row == null) {
// row = firstSheet.createRow(i + 1);
row = firstSheet.createRow(i);
}
System.out.println("check index :: " + indexProperties);
for (int j = 0; j < 1; j++) {
Cell cell = row.getCell(j);
System.out.println("cell :: " + cell);
if (cell == null) {
row.createCell(j).setCellValue(
listProperties.get(indexProperties + 1).toString().trim());
row.createCell(j + 1).setCellValue(
listPropertiesDescription.get(indexProperties + 1).toString().trim());
row.createCell(j + 2).setCellValue(
listPropertiesFileName.get(indexProperties + 1).toString().trim());
}
j++;
}
indexProperties++;
System.out.println("check index below :: " + indexProperties);
i++;
}
int lastRowCount = firstSheet.getLastRowNum();
for (int i = rownum; i < lastRowCount; i++) {
HSSFRow row = firstSheet.getRow(i);
if (row == null) {
removeRow(firstSheet, i);
// firstSheet.shiftRows(i + 1, lastRowCount, -1);
// i--; // Since you move row at i+1 to i
}
}
FileOutputStream fos = null;
try {
File file = new File("OnlineHelp Master Excel.xls");
//if file doesnt exists, then create it
if (!file.exists()) {
file.createNewFile();
}
String fileRB = outputLocation.concat("\\" + file);
fos = new FileOutputStream(new File(fileRB));
workbook.write(fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void removeRow(HSSFSheet sheet, int rowIndex) {
int lastRowNum = sheet.getLastRowNum();
if (rowIndex >= 0 && rowIndex < lastRowNum) {
sheet.shiftRows(rowIndex + 1, lastRowNum, -1);
}
if (rowIndex == lastRowNum) {
HSSFRow removingRow = sheet.getRow(rowIndex);
if (removingRow != null) {
sheet.removeRow(removingRow);
}
}
}
here i attach also result from the above code:
the results:
Row | Result
1 | result a
2 | (empty row)
3 | result b
4 | (empty row)
5 | result b
6 | (empty row)
it only able to removed empty row below result a, the rest still there.
really need help on this. thanks!
ema
I know it is a pretty old thread but ran into this problem this morning. Was not expecting HSSF library to get empty lines. So posting this answer so other members than run into it will have an answer.
Here's my solution - basically copy/paste of parts found around.
HSSFSheet sheet = new HSSFWorkbook(new ByteArrayInputStream(content)).getSheetAt(0);
int headerRowIndex = sheet.getFirstRowNum();
List<String> columnNames = getColumnNames(sheet);
List<Map<String, String>> sheetData = new ArrayList<>();
sheet.forEach(row -> {
if (row.getRowNum() != headerRowIndex && !isRowEmpty(row)) {
sheetData.add(getRowData(row, columnNames));
}
});
... And the method:
private boolean isRowEmpty(Row row) {
for (int cellIndex = row.getFirstCellNum(); cellIndex < row.getLastCellNum(); cellIndex++) {
Cell cell = row.getCell(cellIndex);
if (cell != null && cell.getCellTypeEnum() != CellType.BLANK) {
return false;
}
}
return true;
}
My test file had previously 6 empty rows. They are all gone now :) Enjoy!
I am working on the utility which dumps the excel sheet content to the database (postgres 9.2 in my case) , The application is working very smoothly when all the cells are filled but whenever i am trying to run my code on the excel sheet which is having empty cell it is giving me NULL POINTER EXCEPTION . Can any one help me......?
code.... snips ...
public ArrayList fillList(int colIndex, int id, List<Cell> cells,
String path) {
// OrderedMap errorMap=new LinkedMap();
String error = null;
ArrayList<String> errorList = new ArrayList<String>();
// errorList=null;
try {
FileInputStream fileIn = new FileInputStream(path);
POIFSFileSystem fs;
fs = new POIFSFileSystem(fileIn);
HSSFWorkbook filename = new HSSFWorkbook(fs);
Cell number = null;
HSSFSheet sheet = filename.getSheetAt(0);
Row firstRow = sheet.getRow(0);
int flag = 0;
String errorValue = null;
int columnNo = colIndex;
if (columnNo != -1) {
for (Row row : sheet) {
if (row.getRowNum() != 0) {
Cell c = row.getCell(columnNo);
// row.getCell(arg0, arg1)
// cells.add(c);
System.out.println(c.getCellType());
if (c.getCellType() == Cell.CELL_TYPE_STRING &&
(id == 2 || id == 3)) {
cells.add(c);
} else if (c.getCellType() == Cell.CELL_TYPE_NUMERIC
&& id == 1) {
String s = row.getCell(columnNo).toString();
double d = Double.parseDouble(s);
String mob = Double.toString(d);
Cell sc = row.createCell((short) 2);
String text = NumberToTextConverter.toText(c
.getNumericCellValue());
// System.out.println(text);
sc.setCellValue(text);
cells.add(sc);
// Date date=c.getDateCellValue();
} else if (c.getCellType() == Cell.CELL_TYPE_NUMERIC && id == 4) {
String s = row.getCell(columnNo).toString();
double d = HSSFDateUtil.getExcelDate(c
.getDateCellValue());
// String date = Double.toString(d);
Cell sc = row.createCell((short) 2);
String date = new SimpleDateFormat("dd-MM-yyyy")
.format(c.getDateCellValue());
// System.out.println(text);
sc.setCellValue(date);
cells.add(sc);
}
else if (c.getCellType() == Cell.CELL_TYPE_BLANK && id == 1 ) {
String s = row.getCell(columnNo).toString();
Cell sc = row.createCell((short)2);
sc.setCellValue("-");
cells.add(sc);
}
else {
switch (c.getCellType()) {
case Cell.CELL_TYPE_NUMERIC:
errorValue = Double.toString(c
.getNumericCellValue());
break;
case Cell.CELL_TYPE_STRING:
errorValue = c.getStringCellValue();
break;
}
errorList.add(c.getRowIndex() + "$" + columnNo
+ "$" + errorValue + "$" + id);
}
/*
* if (c == null || c.getCellType() ==
* Cell.CELL_TYPE_BLANK) { cells.add(c); } else {
*
* cells.add(c);
*
* }
*/
flag = 1;
}// if to skip 1st row
}
} else {
// System.out.println("could not find column " + columnWanted +
// " in first row of " + fileIn.toString());
}
return errorList;
} catch (IOException e) {
e.printStackTrace();
} finally {
}
return errorList;
}
Without knowing how you test for null on the cell, then if it throws a NPE on a certain line you should be about to test for null.
if (c == null)
If this really doesn't work then of course you can always catch the NPE
try {
cellType = c.getCellType();
} catch (NullPointerException e) {
// oops Null
// do something else.
}