Problem with FormulaEvaluator cell - Apache POI - java

I have this strange situation and I need some tips on how to resolve it.
I have a column ( lets call it column K ) with values that are result of a FORMULA ( the values of this column are taken from another sheet). All the values on column K are set as String.
I use all the guidelines from the website: https://poi.apache.org/components/spreadsheet/eval.html
but I have a real problem to extract numbers ( example: 12345 ) and data ( 08/09/2022).
When i extract the number 12345 on java i have 12.34.5 and when i extract the date (08/09/2022) it gives me a value: 44813.0
A pseudocode that I was using is this one:
FileInputStream fis = new FileInputStream("/somepath/test.xls");
Workbook wb = new HSSFWorkbook(fis); //or new XSSFWorkbook("/somepath/test.xls")
Sheet sheet = wb.getSheetAt(0);
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
// suppose your formula is in B3
CellReference cellReference = new CellReference("B3");
Row row = sheet.getRow(cellReference.getRow());
Cell cell = row.getCell(cellReference.getCol());
if (cell!=null) {
switch (evaluator.evaluateFormulaCell(cell)) {
case Cell.CELL_TYPE_BOOLEAN:
System.out.println(cell.getBooleanCellValue());
break;
case Cell.CELL_TYPE_NUMERIC:
System.out.println(cell.getNumericCellValue());
break;
case Cell.CELL_TYPE_STRING:
System.out.println(cell.getStringCellValue());
break;
case Cell.CELL_TYPE_BLANK:
break;
case Cell.CELL_TYPE_ERROR:
System.out.println(cell.getErrorCellValue());
break;
// CELL_TYPE_FORMULA will never occur
case Cell.CELL_TYPE_FORMULA:
break;
}
}
Can someone give me some tips on how to resolve it?

Resolved:
Guys, as always some tools has their own logic that if you never work with them you will never know.
The solution was really easy and crazy :)
I select all the content of the column with the formula and other stuff in sheet 1, and i simply paste everything in another sheet 2.
At this moment from all the strange logic about formula, cached stuff, or real content on the cell,... after pasting in another sheet ( sheet 2 ) everything was visibile as a String without any Formula.
So just by doing cell.toString() i get the string value of everything.
Sometimes the easiest solutions are the most hardest thing to reason about lol.

Related

How to retrieve the Date from Excel with Formula by Apache POI

I have an Excel Sheet where the Date Cell is assigned with the Date Formula in Excel TODAY() + 1. So basically today it's showing as 03/10/2018 by default. I've created a code to read the data from Excel which has the formula in it but when I'm getting the date it's coming differently.
Code :
Cell c = CellUtil.getCell(r, columnIndex);
CellType type = c.getCellType();
if (type == CellType.FORMULA) {
switch (c.getCachedFormulaResultType()) {
case NUMERIC:
if (DateUtil.isCellDateFormatted(c)) {
value = (new SimpleDateFormat("dd-MM-yyyy").format(c.getDateCellValue()));
data.add(value); // Date should display 03-10-2018 but it's showing 23-01-2018
} else {
value = (c.getNumericCellValue()) + "";
data.add(value);
}
break;
case STRING:
value = c.getStringCellValue();
data = new LinkedList <String>(Arrays.asList(value.split(";")));
break;
}
}
I don't know why it's showing date from January with the formula applied TODAY() + 1
Similar to this another function TODAY() + 15 returning the 22-04-2018.
As stated in Formula Evaluation:
"The Excel file format (both .xls and .xlsx) stores a "cached" result
for every formula along with the formula itself. This means that when
the file is opened, it can be quickly displayed, without needing to
spend a long time calculating all of the formula results. It also
means that when reading a file through Apache POI, the result is
quickly available to you too!"
So all formulas will have cached results stored from the last time they were evaluated. This is either the last time the workbook was opened in Excel, recalculated and saved or from the last time an evaluation was be done outside of Excel.
So if a cell having the formula =TODAY() has a cached result of 22-01-2018 stored, then the workbook was evaluated on January 22, 2018 the last time.
To get always current formula results you need evaluating the formulas first before reading. Simplest way:
...
workbook.getCreationHelper().createFormulaEvaluator().evaluateAll();
...
Or you are using a DataFormatter together with a FormulaEvaluator:
...
DataFormatter formatter = new DataFormatter();
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
...
Cell cell = CellUtil.getCell(...);
...
String value = formatter.formatCellValue(cell, evaluator);
...

get Result in getCellFormula

I am reading Excel with java, In my Cell I have a formula, but I want get the result -> 20.000 or 2.154, etc, but I get ->
IF(F2="Buy",+(H2-G2+1)*I2,+(H2-G2+1)I2(-1))
switch (cell.getCellType()) {
case Cell.CELL_TYPE_FORMULA:
stringValue = cell.getCellFormula();
break;
....
the problem is that I could't calculated this formula, because I read the excel cell a cell then ... h2-g2... my code doesn't know this...
I am using
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>
how can I get the value of cell ?
Cell.CELL_TYPE_FORMULA: ---> IF(F2="Buy",+(H2-G2+1)*I2,+(H2-G2+1)*I2*(-1))
Cell.CELL_TYPE_STRING: ----> IF(F2="Buy",+(H2-G2+1)*I2,+(H2-G2+1)*I2*(-1))
Thanks!!
EDIT ,
I changed ->
case Cell.CELL_TYPE_FORMULA:
stringValue = String.valueOf(cell.getNumericCellValue());
break;
result -> 5.475E7 this result is bad, my Excel have 54.750.000 visually
The value you get is correct so you're almost there, it's just not formatted as you expect.
Try:
String stringValue = NumberFormat.getNumberInstance().format(cell.getNumericCellValue());

POI-XSSF: read formatted value from formula cells cached value

In my excel sheet many cells contain formulas, i don't want to recalculate these formulas when i read the excel with Apache POI.
The way i do that:
if(cell.getCellType() == XSSFCell.CELL_TYPE_FORMULA) {
//System.out.println("Formula is " + cell.getCellFormula());
switch(cell.getCachedFormulaResultType()) {
case XSSFCell.CELL_TYPE_NUMERIC:
System.out.print(cell.getNumericCellValue() +" ");
break;
case XSSFCell.CELL_TYPE_STRING:
System.out.print(cell.getRichStringCellValue()+" ");
break;
}
}
This helps me in getting the raw value in the cell.
For example if the cell has value 19.5%, this will give me 0.195456 .
I want to get the formatted value.
One way to get the formatted value is:
DataFormatter formatter = new DataFormatter();
System.out.print(formatter.formatCellValue(cell));
This works well for regular cells, but for cells with formulas, this actually gets the formula string and displays it, i.e., it does not get the cached value and formats it, rather it just returns the formula string.
Is there a way to format a value after retrieving it from CELL_TYPE_FORMULA
It's possible to directly format the cached value of a cell without using an evaluator. It's useful in case of values that cannot be recalculated because of third party plugin or unavailable external Data in the cell formula.
This code can be used to do that:
final DataFormatter dataFormatter = new DataFormatter();
final CellStyle cellStyle = cell.getCellStyle();
final String formtatedValue = dataFormatter.formatRawCellContents(cell.getNumericCellValue(), cellStyle.getDataFormat(), cellStyle.getDataFormatString());
System.out.println(formattedValue);
A formatter is still used but the method formatRawCellContents is called to manually format the cell cached value with its style.
It should work if you pass in a FormulaEvaluator in the call to formatCellValue, i.e.
DataFormatter formatter = new DataFormatter();
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
System.out.print(formatter.formatCellValue(cell, evaluator));

Retrieving Values From Excel Apache POI

Im trying to retrieve a specific value from each sheet in excel.
The code works fine for a test excel workbook but does not work with the excel file im trying to retrieve.
The error encountered is,
"Exception in thread "AWT-EventQueue-0" org.apache.poi.ss.formula.FormulaParseException: Specified named range 'Table156723451819202122232434567891011121314151619216710111213162024254567101718193456781112131623242528234789101314151619202128910111215234567891011121314161718192021222324252627282930312345678910111213141516171819202122232425262728293032234567891011140' does not exist in the current workbook."
The target excel book only has 1 month of sheets.(1jan,2jan...)
And the cell im targeting looks like this:
The target cell formula as follows: =SUM(D23:D24)
The following are my codes:
for(int i=0; i<=30; i++){
Sheet sheet = wb.getSheetAt(i);
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
CellReference cellReference = new CellReference("D25");
//CellReference cellReference = new CellReference("A4");
Row row = sheet.getRow(cellReference.getRow());
Cell cell = row.getCell(cellReference.getCol());
//System.out.println("i:"+row.getCell(cellReference.getCol()));
//CellValue cellValue = evaluator.evaluate(cell);
CellValue cellValue = evaluator.evaluate(cell);
switch (cellValue.getCellType()) {
case Cell.CELL_TYPE_BOOLEAN:
System.out.println(cellValue.getBooleanValue());
break;
case Cell.CELL_TYPE_NUMERIC:
System.out.println(cellValue.getNumberValue());
break;
case Cell.CELL_TYPE_STRING:
System.out.println(cellValue.getStringValue());
break;
case Cell.CELL_TYPE_BLANK:
break;
case Cell.CELL_TYPE_ERROR:
break;
// CELL_TYPE_FORMULA will never happen
case Cell.CELL_TYPE_FORMULA:
break;
}
I had tried to put the same formula in my test excel which works fine.
Do give any guidance for this as im stuck at this for very long. Thanks so much!
I figured it out.
Using .XLS format instead of .XLSX solved this problem.
Cheers! Happy Coding.

Apache POI for excel get dependent cells

I am writing a program that reads excel files using apache POI. I'm getting all the values, but I want to know which cells are dependent on others (using the formula for the cell).
I've tried using String formula = cell.getCellFormula(), but this just returns me the cell index (eg. H5). Is there any other way I can do this?
Here's my code for reading cells:
private void handleCell(int type,Cell cell)
{
switch (type)
{
case Cell.CELL_TYPE_STRING:
System.out.print(cell.getStringCellValue() + "\t\t");
break;
case Cell.CELL_TYPE_NUMERIC:
System.out.print(cell.getNumericCellValue() + "\t\t");
break;
case Cell.CELL_TYPE_BOOLEAN:
System.out.print(cell.getBooleanCellValue() + "\t\t");
break;
case Cell.CELL_TYPE_FORMULA:
String form = cell.getCellFormula();
handleCell(cell.getCachedFormulaResultType(),cell);
break;
default :
}
}
have a look at org.apache.poi.ss.formula.FormulaParser.
It has a static method
public static Ptg[] parse(
java.lang.String formula,
FormulaParsingWorkbook workbook,
int formulaType,
int sheetIndex)
according to the documentation, it parses a formula string into a List of tokens in RPN order.
The tokens (Ptg = "parse things") can be checked for their type (REF/VALUE/ARRAY) using public final byte getPtgClass().
I have not tested it, but it may be the way to go. Parse the formula, then check each Ptg entry for the type (REF?) and get the destination cell.
See:
https://poi.apache.org/apidocs/org/apache/poi/ss/formula/FormulaParser.html
https://poi.apache.org/apidocs/org/apache/poi/ss/formula/ptg/Ptg.html

Categories

Resources