I have an existing Excel workbook in which two "output" cells (with range name "rate" and "premium") have formulas based on values in other "input" cells (i.e. range names "loamamount", "loanterm", "age" and "smoker").
If, in the Excel workbook, I make all the input cells empty then the formulae evaluate to "#N/A". However when I populate the correct values in the input cells through poi and use the command
XSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
The value in the two cells is not recalculated and remains "#N/A".
Can anyone help me understand what I am doing wrong? The code is as follows:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;
import org.apache.poi.xssf.usermodel.XSSFName;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class GetDataFromExcel {
public static void main(String[] args) throws IOException {
getData();
}
public static void getData() throws IOException {
String s, cCellName, cString;
XSSFName namedCell;
AreaReference aref;
CellReference[] crefs;
XSSFRow r;
XSSFCell c;
XSSFSheet sheet = null;
File directory = new File("./");
s = directory.getAbsolutePath();
s = s.substring(0, s.length() - 2);
InputStream ExcelFileToRead = new FileInputStream(s + "/src/main/java/Excel/Test1.xlsx");
XSSFWorkbook wb = new XSSFWorkbook(ExcelFileToRead);
// Search for the Range names and set the input values
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("loanamount", 2000000);
map.put("age", 25);
map.put("smoker", "Y");
map.put("loanterm", 23);
for (HashMap.Entry<String, Object> entry : map.entrySet()) {
cCellName = entry.getKey();
namedCell = wb.getName(cCellName);
// Retrieve the cell at the named range and test its contents
aref = new AreaReference(namedCell.getRefersToFormula(), null);
crefs = aref.getAllReferencedCells();
for (int i = 0; i < crefs.length; i++) {
sheet = wb.getSheet(crefs[i].getSheetName());
r = sheet.getRow(crefs[i].getRow());
c = r.getCell(crefs[i].getCol(), Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
// extract the cell contents based on cell type etc.
cString = entry.getValue().toString(); // Add missing cell check
if (c.getCellType() == CellType.STRING) {
c.setCellValue(cString);
} else if (c.getCellType() == CellType.NUMERIC) {
c.setCellValue(Double.parseDouble(cString));
} else if (c.getCellType() == CellType.BOOLEAN) {
c.setCellValue(cString);
} else {
}
}
}
sheet = wb.getSheetAt(0);
XSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
// wb.getCreationHelper().createFormulaEvaluator().evaluateAll();
// Get all the output values requested
Iterator<String> i;
ArrayList<String> outputValues = new ArrayList<String>();
outputValues.add("rate");
outputValues.add("premium");
i = outputValues.iterator();
while (i.hasNext()) {
cCellName = i.next();
namedCell = wb.getName(cCellName);
// retrieve the cell at the named range and test its contents
aref = new AreaReference(namedCell.getRefersToFormula(), null);
crefs = aref.getAllReferencedCells();
for (int j = 0; j < crefs.length; j++) {
sheet = wb.getSheet(crefs[j].getSheetName());
r = sheet.getRow(crefs[j].getRow());
c = r.getCell(crefs[j].getCol(), Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);/////
// extract the cell contents based on cell type etc.
System.out.println(cCellName +" : "+c.getRawValue());
}
}
wb.close();
}
}