Formula evaluation is avaliable on HSSF
(xls) and XSSF
(xlsx). It's not available with
certain restrictions in SXSSF
(streaming xlsx).
1 Working with formulas
Formula evaluation code enables you to calculate the result of formulas in Excels sheets.
For performance, a shared instance of FormulaEvaluator
for a Workbook is used for all evaluations.
The FormulaEvaluator
will cache evaluations of dependent cells, so if you have multiple formulas
all depending on a cell then subsequent evaluations will be faster.
For example, if we are reading a large
Sheet
it has no sense to create a FormulaEvaluator
for every cell being read.
Same way, if we are wirting a large Sheet
it has no sense to notify FormulaEvaluator
cell has chnaged on every cell write.
While this becomes usefull for perfomance reasons, it may become a problem if we are performing changes on data as cached values will not be recalculated. Let's see a simple example:
<script> var wb = new Ax.ms.Excel(); var sheet = wb.createSheet("test"); sheet.getCell("A1").setCellFormula("B1*C1"); sheet.getCell("B1").setCellValue(3); sheet.getCell("C1").setCellValue(5); console.log(sheet.getCell("A1").getCellFormula() + " = " + sheet.getCell("A1").getCellValue()); sheet.getCell("C1").setCellValue(10); console.log(sheet.getCell("A1").getCellFormula() + " = " + sheet.getCell("A1").getCellValue()); </script>
B1*C1 = 15
B1*C1 = 15 (*)
We can see, that we get an invalid result after changing value on cell C1
.
1.1 Reset evaluator
We can reset FormulaEvaluator
any time by calling resetEvaluator()
.
A new FormulaEvaluator
will be created on next need.
<script> var wb = new Ax.ms.Excel(); var sheet = wb.createSheet("test"); sheet.getCell("A1").setCellFormula("B1*C1"); sheet.getCell("B1").setCellValue(3); sheet.getCell("C1").setCellValue(5); console.log(sheet.getCell("A1").getCellFormula() + " = " + sheet.getCell("A1").getCellValue()); wb.resetEvaluator(); sheet.getCell("C1").setCellValue(10); console.log(sheet.getCell("A1").getCellFormula() + " = " + sheet.getCell("A1").getCellValue()); </script>
B1*C1 = 15
B1*C1 = 30
1.2 Disable evaluator cache
You can disable FormulaEvaluator
cache for all operations. Bud doing so,
a new FormulaEvaluator
is created on every call to getCellValue()
.
<script> var wb = new Ax.ms.Excel(); // Disable evaluation cache for all operations wb.setEvaluatorCache(false); var sheet = wb.createSheet("test"); sheet.getCell("A1").setCellFormula("B1*C1"); sheet.getCell("B1").setCellValue(3); sheet.getCell("C1").setCellValue(5); console.log(sheet.getCell("A1").getCellFormula() + " = " + sheet.getCell("A1").getCellValue()); sheet.getCell("C1").setCellValue(10); console.log(sheet.getCell("A1").getCellFormula() + " = " + sheet.getCell("A1").getCellValue()); sheet.getCell("C1").setCellValue(20); console.log(sheet.getCell("A1").getCellFormula() + " = " + sheet.getCell("A1").getCellValue()); </script>
B1*C1 = 15
B1*C1 = 30
B1*C1 = 60
This option may have a performance impact on complex computations.
1.3 Full evaluation
To force re-calculating all formulas in a Workbook you can call method evaluate()
on a Workbook. This will re-evaluate all formulas.
2 Debugging
In the case you experience formula evaluation problems (Java exceptions or just different results), to support an easy detailed analysis, a special logging of the full evaluation is provided.
The output of this logging may be very large (depends on your EXCEL), so this logging has to be explicitly enabled for each single formula evaluation. Should not be used in production - only for specific development use.
TO DO
This section is incomplete and will be concluded as soon as possible.<script> var wb = new Ax.ms.Excel(); // Enable debug -> log will be sent to stdout wb.setEvaluatorDebug(true); var sheet = wb.createSheet("test"); sheet.getCell("A1").setCellFormula("B1*C1"); sheet.getCell("B1").setCellValue(3); sheet.getCell("C1").setCellValue(5); console.log(sheet.getCell("A1").getCellFormula() + " = " + sheet.getCell("A1").getCellValue()); </script>
B1*C1 = 15
3 Examples
The following example, generates a excel sheet with multiplication table formula.
<script> // ================================================================== // Create an Excel workbook and sheet // ================================================================== var wb = new Ax.ms.Excel("multiplication"); var sheet = wb.createSheet("sheet1"); // store in var for convenience const Color = Ax.ms.Excel.Color; const BorderStyle = Ax.ms.Excel.BorderStyle; const FillPatternType = Ax.ms.Excel.FillPatternType; const AxisPosition = Ax.ms.Excel.AxisPosition; const LegendPosition = Ax.ms.Excel.LegendPosition; // ================================================================== // Show Excel enum constants // ================================================================== print("Color =" + Color); print("BoderStyle =" + BorderStyle); print("FillPatternType =" + FillPatternType); print("AxisPosition =" + AxisPosition); print("LegendPosition =" + LegendPosition); // ================================================================== // Create a funny style // ================================================================== var style = wb.createCellStyle(); style.setTopBorderColor(Color.GREEN); style.setBottomBorderColor(Color.RED); style.setLeftBorderColor(Color.BLUE); style.setRightBorderColor(Color.YELLOW); style.setBorderTop(BorderStyle.THICK); style.setBorderBottom(BorderStyle.THICK); style.setBorderLeft(BorderStyle.THICK); style.setBorderRight(BorderStyle.THICK); // ================================================================== // Create the first row/col // ================================================================== var row = sheet.createRow(0); row.addCell("Multiplication"). setCellStyle( wb.createCellStyle(). setFillForegroundColor(Color.AQUA). setFillPattern(Ax.ms.Excel.FillPatternType.SOLID_FOREGROUND) ); // ================================================================== // Create the 1st row with factors // ================================================================== for (var c = 1; c <= 10; c++) { var cell = row.addCell(c); cell.setCellStyle(style); } // ================================================================== // Create 10 rows x 10 cols with multiplication formula // ================================================================== for (var r = 1; r <= 10; r++) { var row = sheet.createRow(r); var cell = row.addCell(r); cell.setCellStyle(style); for (var c = 1; c <= 10; c++) { row.addCellFormula(Ax.text.String.format("%s*%s", Ax.ms.Excel.toCell(r, 0), Ax.ms.Excel.toCell(0, c))); } } // ================================================================== // Evaluate first and ensure all fits // If evaluate it no done, autosize will not take in account the // formulas. // ================================================================== wb.evaluate(); wb.setAutoSizeColumns(); // Show value of D4 ... will be 9 console.log(sheet.getCellValue("D4")); // ================================================================== // Return Excel workbook as a Blob // ================================================================== return wb; </script>
Notice that you can perform Excel computation on server side. This means you can obtain computed results from Excel. In the previous example, to obtain the value of cell D4.
// Show value of D4 ... will be 9 console.log(sheet.getCellValue("D4"));