POI formula evaluator not working - apache-poi

I use poi-ooxml 3.9 to generate invoice report from an excel template I store in db. I have formulas at the end of the sheet that will do sum and other tax calculations.
cell D30 =SUM(D22:D28)
cell D31 =D30*0.12
cell D32 =D31*0.02
cell D33 =D31*0.01
cell D35 =SUM(D30:D33)
Before I write the sheet to a new file I evaluate the formulas, but nothing works. The code below is used to evaluate the formulas. Do I need to evaluate the formulas whenever I write the values into the cells or only at the end of the operation?
String formulaCells[] = { "D30", "D31", "D32", "D33", "D35" };
FormulaEvaluator formulaEvaluator = workBook.getCreationHelper()
.createFormulaEvaluator();
Sheet sheet = workBook.getSheetAt(0);
for (String cellRef : formulaCells) {
CellReference ref = new CellReference(cellRef);
Row actualRow = sheet.getRow(ref.getRow());
Cell cell = actualRow.getCell(ref.getCol());
if (cell != null) {
// here I evaluate the formula
formulaEvaluator.evaluateFormulaCell(cell);
anything I have missed?
Note: Only after I open the generated sheet and press enter in every cells the formulas are evaluated!

Are you sure that your cell are added as number?
if not, try to do something like this:
if(type.equals("String")) {
cell.setCellValue (value.toString());
} else if (type.equals("int")) {
cell.setCellValue(Integer.parseInt(value.toString()));
} else if (type.equals("double")) {
cell.setCellValue(Double.parseDouble(value.toString()));
}

Related

Giving out wrong value when evaluating COUNTIF function using apache poi formula evaluation

I have one excel workbook file in which there are 2 sheets. Sheet 1 has two columns which are just like values and criteria's like
and the other sheet has formula defined as =COUNTIF(Sheet1!A2:A13,Sheet1!B2:B4)
so other sheet looks like
Now when I am reading this second sheet, I want to evaluate the formula to extract the correct values from the workbook but it is giving all wrong values.
Code is as follows:
try {
fis = new FileInputStream(fileName);
workbook = new XSSFWorkbook(fis);
} catch (IOException e) {
e.printStackTrace();
}
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
Iterator<Row> rowIterator = workbook.getSheetAt(1).iterator();
while (rowIterator.hasNext()) {
Row row = rowIterator.next();
Iterator<Cell> cellIterator = row.cellIterator();
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
if (cell.getCellType() == CellType.FORMULA) {
String cellFormula = cell.getCellFormula();
System.out.println("Cell Formula=" + cellFormula);
CellType cellType = evaluator.evaluateFormulaCell(cell);
if (cellType == CellType.NUMERIC) {
System.out.println(cell.getNumericCellValue());
}
} else if (cell.getCellType() == CellType.NUMERIC)
System.out.println(cell.getNumericCellValue());
}
}
closeFIS();
Could some one please point me what wrong I am doing here...
Used as normal worksheet function, COUNTIF does not use a cell range as second parameter but only one value or one cell reference.
If you have =COUNTIF(Sheet1!A2:A13,Sheet1!B2:B4) as formula in a sheet, then you are using that function as dynamic array formula using spilled array behavior. Current Excel versions provide this. But Apache POI (current versions of January 2023) cannot evaluate such formulas properly.
If you would have normal worksheet functions in your Sheet2, such as:
=COUNTIF(Sheet1!A2:A13,Sheet1!B2) in Sheet2!A1
=COUNTIF(Sheet1!A2:A13,Sheet1!B3) in Sheet2!A2
=COUNTIF(Sheet1!A2:A13,Sheet1!B4) in Sheet2!A3
then formula evaluation should work.

Apache POI : Formula gets removed while reading the cell value using formula FormulaEvaluator

I am using poi version 3.17. In my java code I want to read a cell value which has formula and I am using evaluateInCell function of FormulaEvaluator to resolve the cell value.
I have a template excel in my resource in which cells has formulas, if I create a workbook from this and set some value, and try to read it back, the FormulaEvaluator resolve the cell and put the actual value, by this formula of those cells get replaced and updated with actual value. WHY??
I have seen the implementation of evaluateInCell function which intentionally setting the cell type as setCellType(cell, cv);
public XSSFCell evaluateInCell(Cell cell) {
if (cell == null) {
return null;
} else {
XSSFCell result = (XSSFCell)cell;
if (cell.getCellType() == 2) {
CellValue cv = this.evaluateFormulaCellValue(cell);
setCellType(cell, cv);
setCellValue(cell, cv);
}
return result;
}
}
Why library is doing so, and removing actual formula from the cell.
There are different functions:
CellType evaluateFormulaCell(Cell cell) - your cell will hold both the formula, and the result.
Cell evaluateInCell(Cell cell) - you cell will contain result only, formula is erased.
CellValue evaluate(Cell cell) - the formula is evaluated and returned. No changes in the cell.
void evaluateAll() = mass evaluateFormulaCell for the whole book.
Obviously, you have taken evaluateInCell for evaluateFormulaCell. evaluateInCell is very useful, and not only for counting - Use it for clean erasing of formulae.
Also, don't forget clearAllCachedResultValues() or notifyUpdateCell()/notifySetFormula(). Without those, any evaluation after any changes on the sheet can fail.

Aspose CheckCell vs Aspose WorkSheet.Cell[r,c]

My excel has millions of records (approx 1.1M) and when I am trying to read cell by cell using WorkSheet.Cells[row,cloumn] it is very slow.
Rather if I use, WorkSheet.Cells.CheckCell(row, column) performance is very good.
Can you please let me know the difference between these two API's
Worksheet.Cells.CheckCell() is the most right way to check if the cell exists or not.
CheckCell method will not instantiate the cell if it does not exist. On the other hand, Cells[r, c] will instantiate the cell if it does not exist.
It means,
CheckCell can return null or cell object.
But Cells[r, c] will never return null and will always return cell object.
Since Cells[r, c] will always return cell object and if it does not already exist, it will create it, this is why, it affects the performance. If you want to iterate all the existing cells in your worksheet without creating new cells, please use Worksheet.Cells.GetEnumerator() method.
Please see the following sample code, its comments and console output for a reference.
C#
//Create a workbook
Workbook wb = new Workbook();
//Access first worksheet
Worksheet ws = wb.Worksheets[0];
//At the moment, Cell B4 does not exist
//Therefore check cell will return null
Cell cell = ws.Cells.CheckCell(3, 1);
Console.WriteLine(cell == null); //<<<<<<<<<< It will print - True
//After this statement, cell B4 will be instantiated and it will exist
var o = ws.Cells[3, 1];
//Now check cell will not return null, but it will return cell B4
cell = ws.Cells.CheckCell(3, 1);
Console.WriteLine(cell == null);//<<<<<<<<<< It will print - False
Console Output
True
False
Update - 1
Please see the following sample code, its comments and console output. It illustrates that GetEnumerator() method returns non-empty and empty cells as well.
C#
//Create a workbook
Workbook wb = new Workbook();
//Access first worksheet
Worksheet ws = wb.Worksheets[0];
//Create empty cells
//Cell A4, B6, C8 and D10 all are empty
var o = ws.Cells["A4"];
o = ws.Cells["B6"];
o = ws.Cells["C8"];
o = ws.Cells["D10"];
//Get cells enumerator
var i = ws.Cells.GetEnumerator();
//Iterate all cells
while(i.MoveNext())
{
Cell cell = i.Current as Cell;
//Print cell name
Debug.WriteLine(cell.Name);
}
Console Output
A4
B6
C8
D10
Note: I am working as Developer Evangelist at Aspose

Complex cell formula evaluation does not work using apache-poi

I am using apache-poi api (v3.9) in my project to process the excel template. I do update the all required cell values in all sheets of my excel document. I am using some complex formulas to calculate the double value for some cell.
I am facing the problem in reading the cell value of a cell having some complex formula. This complex formula works fine in excel sheet but return zero when I read it using poi.
Complex formula which I am using:
"=SUMPRODUCT(--('A-La-Carte'!$L$12:$L$100000=E129)*IF('A-La-Carte'!$K$12:$K$100000<>"-",'A-La-Carte'!$K$12:$K$100000,0)*IF(ISNUMBER(INT(LEFT('A-La-Carte'!$D$12:$D$100000,2))),12/INT(LEFT('A-La-Carte'!$D$12:$D$100000,2)),0))+(NOW()*0)"
If I change the above formula with some simple formula it works fine.
Below is the sample code which I used to read the cell value:
XSSFFormulaEvaluator.evaluateAllFormulaCells(workbook);
private String getCellValue(String cellRef,
XSSFWorkbook workbook,String sheetName) {
XSSFSheet xssfSheet = workbook.getSheet(sheetName);
CellReference cellReference = new CellReference(cellRef);
XSSFRow r = xssfSheet.getRow(cellReference.getRow());
if (r != null) {
XSSFCell c = r.getCell(cellReference.getCol());
if(c.getCellType()==XSSFCell.CELL_TYPE_NUMERIC)
return c.getNumericCellValue()+"";
else if((c.getCellType()==XSSFCell.CELL_TYPE_FORMULA)){
return c. getNumericCellValue()+"";
}
return c.getStringCellValue();
}
return null;
}
Can anybody tell me whats wrong with formula or API?

How to remove value from datagridview cell on cell click?

I have a datagridview column which value is showing 0.00 when form load which is a decimal value. I want to clear this column cell value when I click on particular cell and when I leave the cell the value(0.00) should come in the cell. I am attaching a snap shot for better understanding.
I want this on particular cell click. Is it possible with decimal values? How can I set a cell as empty? I have done some code on cell click but no result.
private void dgvForecast_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 3)
{
var cell = dgvForecast.Rows[e.RowIndex].Cells[e.ColumnIndex].Style as DataGridViewCellStyle;
decimal val = Convert.ToDecimal(dgvForecast.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString());
cell.Format = "";
dgvForecast.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = val.ToString("#");
cell.ApplyStyle(cell);
}
}
for deleting the cell value you can use
if (e.ColumnIndex == 3)
{
dataGridVirtuals[e.ColumnIndex, e.RowIndex].Value = "";
}
for putting up a value into the cell that loses focus you can use CellLeave event
eg
if(e.ColumnIndex==3)
{
dataGridView[e.ColumnIndex,e.RowIndex].Value=[yourvalue];
}

Resources