2005-05-13 10:52:42 -04:00
|
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
2007-01-15 18:11:09 -05:00
|
|
|
<!--
|
|
|
|
====================================================================
|
|
|
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
|
|
|
contributor license agreements. See the NOTICE file distributed with
|
|
|
|
this work for additional information regarding copyright ownership.
|
|
|
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
|
|
|
(the "License"); you may not use this file except in compliance with
|
|
|
|
the License. You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
====================================================================
|
|
|
|
-->
|
2005-05-13 10:52:42 -04:00
|
|
|
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.1//EN" "../dtd/document-v11.dtd">
|
|
|
|
|
|
|
|
<document>
|
|
|
|
<header>
|
|
|
|
<title>Formula Evaluation</title>
|
|
|
|
<authors>
|
|
|
|
<person email="amoweb@yahoo.com" name="Amol Deshmukh" id="AD"/>
|
|
|
|
</authors>
|
|
|
|
</header>
|
|
|
|
<body>
|
|
|
|
<section><title>Introduction</title>
|
|
|
|
<p>The POI formula evaluation code enables you to calculate the result of
|
|
|
|
formulas in Excels sheets read-in, or created in POI. This document explains
|
|
|
|
how to use the API to evaluate your formulas.
|
|
|
|
</p>
|
2008-11-11 06:43:20 -05:00
|
|
|
<note>.xlsx format is suported since POI 3.5, make sure yoy upgraded to that version before experimenting with this
|
2008-03-29 14:27:38 -04:00
|
|
|
code. Users of all versions of POI may wish to make use of a recent
|
|
|
|
SVN checkout, as new functions are currently being added fairly frequently.
|
2005-05-24 10:23:03 -04:00
|
|
|
</note>
|
2005-05-13 10:52:42 -04:00
|
|
|
</section>
|
2008-01-09 15:50:00 -05:00
|
|
|
|
|
|
|
<anchor id="Status"/>
|
2005-05-13 10:52:42 -04:00
|
|
|
<section><title>Status</title>
|
|
|
|
<p> The code currently provides implementations for all the arithmatic operators.
|
2008-01-09 15:37:06 -05:00
|
|
|
It also provides implementations for approx. 100 built in
|
2005-05-13 10:52:42 -04:00
|
|
|
functions in Excel. The framework however makes is easy to add
|
|
|
|
implementation of new functions. See the <link href="eval-devguide.html"> Formula
|
2008-11-11 06:43:20 -05:00
|
|
|
evaluation development guide</link> and <link href="../apidocs/org/apache/poi/hssf/record/formula/functions/package-summary.html">javadocs</link>
|
|
|
|
for details. </p>
|
2008-03-29 18:50:44 -04:00
|
|
|
<p> Both HSSFWorkbook and XSSFWorkbook are supported, so you can
|
|
|
|
evaluate formulas on both .xls and .xlsx files.</p>
|
2005-05-13 10:52:42 -04:00
|
|
|
<p> Note that user-defined functions are not supported, and is not likely to done
|
|
|
|
any time soon... at least, not till there is a VB implementation in Java!
|
|
|
|
</p>
|
|
|
|
</section>
|
|
|
|
<section><title>User API How-TO</title>
|
2008-03-29 18:50:44 -04:00
|
|
|
<p>The following code demonstrates how to use the FormulaEvaluator
|
2005-05-13 10:52:42 -04:00
|
|
|
in the context of other POI excel reading code.
|
|
|
|
</p>
|
2008-03-29 18:50:44 -04:00
|
|
|
<p>There are several ways in which you can use the FormulaEvalutator API.</p>
|
2008-01-09 15:50:00 -05:00
|
|
|
|
|
|
|
<anchor id="Evaluate"/>
|
2008-03-29 18:50:44 -04:00
|
|
|
<section><title>Using FormulaEvaluator.<strong>evaluate</strong>(Cell cell)</title>
|
2008-01-25 06:39:29 -05:00
|
|
|
<p>This evaluates a given cell, and returns the new value,
|
|
|
|
without affecting the cell</p>
|
2005-05-13 10:52:42 -04:00
|
|
|
<source>
|
|
|
|
FileInputStream fis = new FileInputStream("c:/temp/test.xls");
|
2008-11-11 06:43:20 -05:00
|
|
|
Workbook wb = new HSSFWorkbook(fis); //or new XSSFWorkbook("c:/temp/test.xls")
|
2008-03-29 18:50:44 -04:00
|
|
|
Sheet sheet = wb.getSheetAt(0);
|
2008-11-11 06:43:20 -05:00
|
|
|
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
|
2005-05-13 10:52:42 -04:00
|
|
|
|
|
|
|
// suppose your formula is in B3
|
|
|
|
CellReference cellReference = new CellReference("B3");
|
2008-03-29 18:50:44 -04:00
|
|
|
Row row = sheet.getRow(cellReference.getRow());
|
|
|
|
Cell cell = row.getCell(cellReference.getCol());
|
2007-12-13 08:17:49 -05:00
|
|
|
|
2008-11-11 06:43:20 -05:00
|
|
|
CellValue cellValue = evaluator.evaluate(cell);
|
2005-05-13 10:52:42 -04:00
|
|
|
|
|
|
|
switch (cellValue.getCellType()) {
|
2008-11-11 06:43:20 -05:00
|
|
|
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;
|
2005-05-13 10:52:42 -04:00
|
|
|
}
|
2008-11-11 06:43:20 -05:00
|
|
|
</source>
|
2005-05-13 10:52:42 -04:00
|
|
|
<p>Thus using the retrieved value (of type
|
2008-03-29 18:50:44 -04:00
|
|
|
FormulaEvaluator.CellValue - a nested class) returned
|
|
|
|
by FormulaEvaluator is similar to using a Cell object
|
2005-05-13 10:52:42 -04:00
|
|
|
containing the value of the formula evaluation. CellValue is
|
|
|
|
a simple value object and does not maintain reference
|
|
|
|
to the original cell.
|
|
|
|
</p>
|
|
|
|
</section>
|
2008-01-09 15:50:00 -05:00
|
|
|
|
2008-01-25 06:39:29 -05:00
|
|
|
<anchor id="EvaluateFormulaCell"/>
|
2008-03-29 18:50:44 -04:00
|
|
|
<section><title>Using FormulaEvaluator.<strong>evaluateFormulaCell</strong>(Cell cell)</title>
|
|
|
|
<p><strong>evaluateFormulaCell</strong>(Cell cell)
|
2008-01-25 06:39:29 -05:00
|
|
|
will check to see if the supplied cell is a formula cell.
|
|
|
|
If it isn't, then no changes will be made to it. If it is,
|
|
|
|
then the formula is evaluated. The value for the formula
|
|
|
|
is saved alongside it, to be displayed in excel. The
|
|
|
|
formula remains in the cell, just with a new value</p>
|
|
|
|
<p>The return of the function is the type of the
|
2008-03-29 18:50:44 -04:00
|
|
|
formula result, such as Cell.CELL_TYPE_BOOLEAN</p>
|
2008-11-11 06:43:20 -05:00
|
|
|
<source>
|
2008-01-25 06:39:29 -05:00
|
|
|
FileInputStream fis = new FileInputStream("/somepath/test.xls");
|
2008-11-11 06:43:20 -05:00
|
|
|
Workbook wb = new HSSFWorkbook(fis); //or new XSSFWorkbook("/somepath/test.xls")
|
2008-03-29 18:50:44 -04:00
|
|
|
Sheet sheet = wb.getSheetAt(0);
|
2008-11-11 06:43:20 -05:00
|
|
|
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
|
2008-01-25 06:39:29 -05:00
|
|
|
|
|
|
|
// suppose your formula is in B3
|
|
|
|
CellReference cellReference = new CellReference("B3");
|
2008-03-29 18:50:44 -04:00
|
|
|
Row row = sheet.getRow(cellReference.getRow());
|
|
|
|
Cell cell = row.getCell(cellReference.getCol());
|
2008-01-25 06:39:29 -05:00
|
|
|
|
|
|
|
if (cell!=null) {
|
2008-11-11 06:43:20 -05:00
|
|
|
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;
|
|
|
|
}
|
2008-01-25 06:39:29 -05:00
|
|
|
}
|
|
|
|
</source>
|
|
|
|
</section>
|
|
|
|
|
2008-01-09 15:50:00 -05:00
|
|
|
<anchor id="EvaluateInCell"/>
|
2008-03-29 18:50:44 -04:00
|
|
|
<section><title>Using FormulaEvaluator.<strong>evaluateInCell</strong>(Cell cell)</title>
|
|
|
|
<p><strong>evaluateInCell</strong>(Cell cell) will check to
|
2008-01-09 15:37:06 -05:00
|
|
|
see if the supplied cell is a formula cell. If it isn't,
|
|
|
|
then no changes will be made to it. If it is, then the
|
2008-01-25 06:39:29 -05:00
|
|
|
formula is evaluated, and the new value saved into the cell,
|
|
|
|
in place of the old formula.</p>
|
2005-05-13 10:52:42 -04:00
|
|
|
<source>
|
2005-05-19 06:36:06 -04:00
|
|
|
FileInputStream fis = new FileInputStream("/somepath/test.xls");
|
2008-11-11 06:43:20 -05:00
|
|
|
Workbook wb = new HSSFWorkbook(fis); //or new XSSFWorkbook("/somepath/test.xls")
|
2008-03-29 18:50:44 -04:00
|
|
|
Sheet sheet = wb.getSheetAt(0);
|
2008-11-11 06:43:20 -05:00
|
|
|
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
|
2005-05-13 10:52:42 -04:00
|
|
|
|
|
|
|
// suppose your formula is in B3
|
2008-11-11 06:43:20 -05:00
|
|
|
CellReference cellReference = new CellReference("B3");
|
2008-03-29 18:50:44 -04:00
|
|
|
Row row = sheet.getRow(cellReference.getRow());
|
|
|
|
Cell cell = row.getCell(cellReference.getCol());
|
2005-05-13 10:52:42 -04:00
|
|
|
|
|
|
|
if (cell!=null) {
|
2008-11-11 06:43:20 -05:00
|
|
|
switch (evaluator.<strong>evaluateInCell</strong>(cell).getCellType()) {
|
|
|
|
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;
|
|
|
|
}
|
2005-05-13 10:52:42 -04:00
|
|
|
}
|
2008-11-11 06:43:20 -05:00
|
|
|
|
|
|
|
</source>
|
2008-01-09 15:37:06 -05:00
|
|
|
</section>
|
2008-01-09 15:50:00 -05:00
|
|
|
|
|
|
|
<anchor id="EvaluateAll"/>
|
2008-01-09 15:37:06 -05:00
|
|
|
<section><title>Re-calculating all formulas in a Workbook</title>
|
|
|
|
<source>
|
|
|
|
FileInputStream fis = new FileInputStream("/somepath/test.xls");
|
2008-11-11 06:43:20 -05:00
|
|
|
Workbook wb = new HSSFWorkbook(fis); //or new XSSFWorkbook("/somepath/test.xls")
|
|
|
|
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
|
2008-01-09 15:37:06 -05:00
|
|
|
for(int sheetNum = 0; sheetNum < wb.getNumberOfSheets(); sheetNum++) {
|
2008-11-11 06:43:20 -05:00
|
|
|
Sheet sheet = wb.getSheetAt(sheetNum);
|
|
|
|
for(Row r : sheet) {
|
|
|
|
for(Cell c : r) {
|
|
|
|
if(c.getCellType() == Cell.CELL_TYPE_FORMULA) {
|
|
|
|
evaluator.evaluateFormulaCell(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-01-09 15:37:06 -05:00
|
|
|
}
|
2008-11-11 06:43:20 -05:00
|
|
|
</source>
|
2011-05-09 10:04:21 -04:00
|
|
|
|
|
|
|
<p>Alternately, if you know which of HSSF or XSSF you're working
|
|
|
|
with, then you can call the static
|
|
|
|
<strong>evaluateAllFormulaCells</strong> method on the appropriate
|
|
|
|
HSSFFormulaEvaluator or XSSFFormulaEvaluator class.</p>
|
2008-01-09 15:37:06 -05:00
|
|
|
</section>
|
2005-05-13 10:52:42 -04:00
|
|
|
</section>
|
|
|
|
|
2011-06-27 11:40:48 -04:00
|
|
|
<anchor id="recalculation"/>
|
|
|
|
<section><title>Recalculation of Formulas</title>
|
|
|
|
<p>
|
|
|
|
In certain cases you may want to force Excel to re-calculate formulas when the workbook is opened.
|
|
|
|
Consider the following example:
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
Open Excel and create a new workbook. On the first sheet set A1=1, B1=1, C1=A1+B1.
|
|
|
|
Excel automatically calculates formulas and the value in C1 is 2. So far so good.
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
Now modify the workbook with POI:
|
|
|
|
</p>
|
|
|
|
<source>
|
|
|
|
Workbook wb = WorkbookFactory.create(new FileInputStream("workbook.xls"));
|
|
|
|
|
|
|
|
Sheet sh = wb.getSheetAt(0);
|
|
|
|
sh.getRow(0).getCell(0).setCellValue(2); // set A1=2
|
|
|
|
|
|
|
|
FileOutputStream out = new FileOutputStream("workbook2.xls");
|
|
|
|
wb.write(out);
|
|
|
|
out.close();
|
|
|
|
</source>
|
|
|
|
<p>
|
|
|
|
Now open workbook2.xls in Excel and the value in C1 is still 2 while you expected 3. Wrong? No!
|
|
|
|
The point is that Excel caches previously calculated results and you need to trigger recalculation to updated them.
|
|
|
|
It is not an issue when you are creating new workbooks from scratch, but important to remember when you are modifing
|
|
|
|
existing workbooks with formulas. This can be done in two ways:
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
1. Re-evaluate formuals with POI's FormulaEvaluator:
|
|
|
|
</p>
|
|
|
|
<source>
|
|
|
|
Workbook wb = WorkbookFactory.create(new FileInputStream("workbook.xls"));
|
|
|
|
|
|
|
|
Sheet sh = wb.getSheetAt(0);
|
|
|
|
sh.getRow(0).getCell(0).setCellValue(2); // set A1=2
|
|
|
|
|
|
|
|
wb.getCreationHelper().createFormulaEvaluator().evaluateAll();
|
|
|
|
</source>
|
|
|
|
<p>
|
|
|
|
2. Delegate re-calculation to Excel. The application will perform a full recalculation when the workbook is opened:
|
|
|
|
</p>
|
|
|
|
<source>
|
|
|
|
Workbook wb = WorkbookFactory.create(new FileInputStream("workbook.xls"));
|
|
|
|
|
|
|
|
Sheet sh = wb.getSheetAt(0);
|
|
|
|
sh.getRow(0).getCell(0).setCellValue(2); // set A1=2
|
|
|
|
|
|
|
|
wb.setForceFormulaRecalculation(true);
|
|
|
|
</source>
|
|
|
|
</section>
|
|
|
|
|
2008-01-09 15:50:00 -05:00
|
|
|
<anchor id="Performance"/>
|
2005-05-13 10:52:42 -04:00
|
|
|
<section><title>Performance Notes</title>
|
|
|
|
<ul>
|
2008-03-29 18:50:44 -04:00
|
|
|
<li>Generally you should have to create only one FormulaEvaluator
|
2005-05-13 10:52:42 -04:00
|
|
|
instance per sheet, but there really is no overhead in creating
|
2008-03-29 18:50:44 -04:00
|
|
|
multiple FormulaEvaluators per sheet other than that of the
|
|
|
|
FormulaEvaluator object creation.
|
2005-05-13 10:52:42 -04:00
|
|
|
</li>
|
2008-03-29 18:50:44 -04:00
|
|
|
<li>Also note that FormulaEvaluator maintains a reference to
|
2005-05-13 10:52:42 -04:00
|
|
|
the sheet and workbook, so ensure that the evaluator instance
|
|
|
|
is available for garbage collection when you are done with it
|
|
|
|
(in other words don't maintain long lived reference to
|
2008-03-29 18:50:44 -04:00
|
|
|
FormulaEvaluator if you don't really need to - unless
|
2005-05-13 10:52:42 -04:00
|
|
|
all references to the sheet and workbook are removed, these
|
|
|
|
don't get garbage collected and continue to occupy potentially
|
|
|
|
large amounts of memory).
|
|
|
|
</li>
|
|
|
|
<li>CellValue instances however do not maintain reference to the
|
2008-03-29 18:50:44 -04:00
|
|
|
Cell or the sheet or workbook, so these can be long-lived
|
2005-05-13 10:52:42 -04:00
|
|
|
objects without any adverse effect on performance.
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</section>
|
|
|
|
</body>
|
|
|
|
</document>
|