Switch XSSF onto BaseFormulaEvaluator, reducing code duplication and fixing XSSFFormulaEvaluator.evaluateAll() to mirror HSSF and use any setup referenced workbooks (stackoverflow #38706562)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1755079 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
60b2586c3f
commit
a1f6d9c832
@ -33,8 +33,6 @@ import org.apache.poi.ss.usermodel.Cell;
|
|||||||
import org.apache.poi.ss.usermodel.CellType;
|
import org.apache.poi.ss.usermodel.CellType;
|
||||||
import org.apache.poi.ss.usermodel.CellValue;
|
import org.apache.poi.ss.usermodel.CellValue;
|
||||||
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
||||||
import org.apache.poi.ss.usermodel.Row;
|
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
|
||||||
import org.apache.poi.ss.usermodel.Workbook;
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
import org.apache.poi.util.Internal;
|
import org.apache.poi.util.Internal;
|
||||||
|
|
||||||
@ -248,21 +246,7 @@ public class HSSFFormulaEvaluator extends BaseFormulaEvaluator {
|
|||||||
* cells, and calling evaluateFormulaCell on each one.
|
* cells, and calling evaluateFormulaCell on each one.
|
||||||
*/
|
*/
|
||||||
public static void evaluateAllFormulaCells(Workbook wb) {
|
public static void evaluateAllFormulaCells(Workbook wb) {
|
||||||
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
|
BaseFormulaEvaluator.evaluateAllFormulaCells(wb);
|
||||||
evaluateAllFormulaCells(wb, evaluator);
|
|
||||||
}
|
|
||||||
private static void evaluateAllFormulaCells(Workbook wb, FormulaEvaluator evaluator) {
|
|
||||||
for(int i=0; i<wb.getNumberOfSheets(); i++) {
|
|
||||||
Sheet sheet = wb.getSheetAt(i);
|
|
||||||
|
|
||||||
for(Row r : sheet) {
|
|
||||||
for (Cell c : r) {
|
|
||||||
if (c.getCellTypeEnum() == CellType.FORMULA) {
|
|
||||||
evaluator.evaluateFormulaCellEnum(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -142,8 +142,10 @@ public abstract class BaseFormulaEvaluator implements FormulaEvaluator, Workbook
|
|||||||
return;
|
return;
|
||||||
case BLANK:
|
case BLANK:
|
||||||
// never happens - blanks eventually get translated to zero
|
// never happens - blanks eventually get translated to zero
|
||||||
|
throw new IllegalArgumentException("This should never happen. Blanks eventually get translated to zero.");
|
||||||
case FORMULA:
|
case FORMULA:
|
||||||
// this will never happen, we have already evaluated the formula
|
// this will never happen, we have already evaluated the formula
|
||||||
|
throw new IllegalArgumentException("This should never happen. Formulas should have already been evaluated.");
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
|
throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
|
||||||
}
|
}
|
||||||
@ -164,7 +166,7 @@ public abstract class BaseFormulaEvaluator implements FormulaEvaluator, Workbook
|
|||||||
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
|
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
|
||||||
evaluateAllFormulaCells(wb, evaluator);
|
evaluateAllFormulaCells(wb, evaluator);
|
||||||
}
|
}
|
||||||
private static void evaluateAllFormulaCells(Workbook wb, FormulaEvaluator evaluator) {
|
protected static void evaluateAllFormulaCells(Workbook wb, FormulaEvaluator evaluator) {
|
||||||
for(int i=0; i<wb.getNumberOfSheets(); i++) {
|
for(int i=0; i<wb.getNumberOfSheets(); i++) {
|
||||||
Sheet sheet = wb.getSheetAt(i);
|
Sheet sheet = wb.getSheetAt(i);
|
||||||
|
|
||||||
|
@ -17,12 +17,9 @@
|
|||||||
|
|
||||||
package org.apache.poi.xssf.usermodel;
|
package org.apache.poi.xssf.usermodel;
|
||||||
|
|
||||||
import java.util.Map;
|
import org.apache.poi.ss.formula.BaseFormulaEvaluator;
|
||||||
|
|
||||||
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment;
|
|
||||||
import org.apache.poi.ss.formula.EvaluationCell;
|
import org.apache.poi.ss.formula.EvaluationCell;
|
||||||
import org.apache.poi.ss.formula.WorkbookEvaluator;
|
import org.apache.poi.ss.formula.WorkbookEvaluator;
|
||||||
import org.apache.poi.ss.formula.WorkbookEvaluatorProvider;
|
|
||||||
import org.apache.poi.ss.formula.eval.BoolEval;
|
import org.apache.poi.ss.formula.eval.BoolEval;
|
||||||
import org.apache.poi.ss.formula.eval.ErrorEval;
|
import org.apache.poi.ss.formula.eval.ErrorEval;
|
||||||
import org.apache.poi.ss.formula.eval.NumberEval;
|
import org.apache.poi.ss.formula.eval.NumberEval;
|
||||||
@ -31,28 +28,16 @@ import org.apache.poi.ss.formula.eval.ValueEval;
|
|||||||
import org.apache.poi.ss.usermodel.Cell;
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
import org.apache.poi.ss.usermodel.CellType;
|
import org.apache.poi.ss.usermodel.CellType;
|
||||||
import org.apache.poi.ss.usermodel.CellValue;
|
import org.apache.poi.ss.usermodel.CellValue;
|
||||||
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
|
||||||
import org.apache.poi.util.Internal;
|
import org.apache.poi.util.Internal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal POI use only - parent of XSSF and SXSSF formula evaluators
|
* Internal POI use only - parent of XSSF and SXSSF formula evaluators
|
||||||
*/
|
*/
|
||||||
public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, WorkbookEvaluatorProvider {
|
public abstract class BaseXSSFFormulaEvaluator extends BaseFormulaEvaluator {
|
||||||
private WorkbookEvaluator _bookEvaluator;
|
|
||||||
|
|
||||||
protected BaseXSSFFormulaEvaluator(WorkbookEvaluator bookEvaluator) {
|
protected BaseXSSFFormulaEvaluator(WorkbookEvaluator bookEvaluator) {
|
||||||
_bookEvaluator = bookEvaluator;
|
super(bookEvaluator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Should be called whenever there are major changes (e.g. moving sheets) to input cells
|
|
||||||
* in the evaluated workbook.
|
|
||||||
* Failure to call this method after changing cell values will cause incorrect behaviour
|
|
||||||
* of the evaluate~ methods of this class
|
|
||||||
*/
|
|
||||||
public void clearAllCachedResultValues() {
|
|
||||||
_bookEvaluator.clearAllCachedResultValues();
|
|
||||||
}
|
|
||||||
public void notifySetFormula(Cell cell) {
|
public void notifySetFormula(Cell cell) {
|
||||||
_bookEvaluator.notifyUpdateCell(new XSSFEvaluationCell((XSSFCell)cell));
|
_bookEvaluator.notifyUpdateCell(new XSSFEvaluationCell((XSSFCell)cell));
|
||||||
}
|
}
|
||||||
@ -63,60 +48,6 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
|
|||||||
_bookEvaluator.notifyUpdateCell(new XSSFEvaluationCell((XSSFCell)cell));
|
_bookEvaluator.notifyUpdateCell(new XSSFEvaluationCell((XSSFCell)cell));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If cell contains a formula, the formula is evaluated and returned,
|
|
||||||
* else the CellValue simply copies the appropriate cell value from
|
|
||||||
* the cell and also its cell type. This method should be preferred over
|
|
||||||
* evaluateInCell() when the call should not modify the contents of the
|
|
||||||
* original cell.
|
|
||||||
* @param cell
|
|
||||||
*/
|
|
||||||
public CellValue evaluate(Cell cell) {
|
|
||||||
if (cell == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (cell.getCellTypeEnum()) {
|
|
||||||
case BOOLEAN:
|
|
||||||
return CellValue.valueOf(cell.getBooleanCellValue());
|
|
||||||
case ERROR:
|
|
||||||
return CellValue.getError(cell.getErrorCellValue());
|
|
||||||
case FORMULA:
|
|
||||||
return evaluateFormulaCellValue(cell);
|
|
||||||
case NUMERIC:
|
|
||||||
return new CellValue(cell.getNumericCellValue());
|
|
||||||
case STRING:
|
|
||||||
return new CellValue(cell.getRichStringCellValue().getString());
|
|
||||||
case BLANK:
|
|
||||||
return null;
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Bad cell type (" + cell.getCellTypeEnum() + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If cell contains formula, it evaluates the formula,
|
|
||||||
* and saves the result of the formula. The cell
|
|
||||||
* remains as a formula cell.
|
|
||||||
* Else if cell does not contain formula, this method leaves
|
|
||||||
* the cell unchanged.
|
|
||||||
* Note that the type of the formula result is returned,
|
|
||||||
* so you know what kind of value is also stored with
|
|
||||||
* the formula.
|
|
||||||
* <pre>
|
|
||||||
* int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
|
|
||||||
* </pre>
|
|
||||||
* Be aware that your cell will hold both the formula,
|
|
||||||
* and the result. If you want the cell replaced with
|
|
||||||
* the result of the formula, use {@link #evaluate(org.apache.poi.ss.usermodel.Cell)} }
|
|
||||||
* @param cell The cell to evaluate
|
|
||||||
* @return The type of the formula result (the cell's type remains as CellType.FORMULA however)
|
|
||||||
*/
|
|
||||||
public int evaluateFormulaCell(Cell cell) {
|
|
||||||
return evaluateFormulaCellEnum(cell).getCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If cell contains formula, it evaluates the formula,
|
* If cell contains formula, it evaluates the formula,
|
||||||
* and saves the result of the formula. The cell
|
* and saves the result of the formula. The cell
|
||||||
@ -164,27 +95,6 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
|
|||||||
setCellValue(cell, cv);
|
setCellValue(cell, cv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static void setCellType(Cell cell, CellValue cv) {
|
|
||||||
CellType cellType = cv.getCellType();
|
|
||||||
switch (cellType) {
|
|
||||||
case BOOLEAN:
|
|
||||||
case ERROR:
|
|
||||||
case NUMERIC:
|
|
||||||
case STRING:
|
|
||||||
cell.setCellType(cellType);
|
|
||||||
return;
|
|
||||||
case BLANK:
|
|
||||||
// never happens - blanks eventually get translated to zero
|
|
||||||
throw new IllegalArgumentException("This should never happen. Blanks eventually get translated to zero.");
|
|
||||||
case FORMULA:
|
|
||||||
// this will never happen, we have already evaluated the formula
|
|
||||||
throw new IllegalArgumentException("This should never happen. Formulas should have already been evaluated.");
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void setCellValue(Cell cell, CellValue cv) {
|
private static void setCellValue(Cell cell, CellValue cv) {
|
||||||
CellType cellType = cv.getCellType();
|
CellType cellType = cv.getCellType();
|
||||||
@ -218,7 +128,7 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
|
|||||||
/**
|
/**
|
||||||
* Returns a CellValue wrapper around the supplied ValueEval instance.
|
* Returns a CellValue wrapper around the supplied ValueEval instance.
|
||||||
*/
|
*/
|
||||||
private CellValue evaluateFormulaCellValue(Cell cell) {
|
protected CellValue evaluateFormulaCellValue(Cell cell) {
|
||||||
EvaluationCell evalCell = toEvaluationCell(cell);
|
EvaluationCell evalCell = toEvaluationCell(cell);
|
||||||
ValueEval eval = _bookEvaluator.evaluate(evalCell);
|
ValueEval eval = _bookEvaluator.evaluate(evalCell);
|
||||||
if (eval instanceof NumberEval) {
|
if (eval instanceof NumberEval) {
|
||||||
@ -238,22 +148,4 @@ public abstract class BaseXSSFFormulaEvaluator implements FormulaEvaluator, Work
|
|||||||
}
|
}
|
||||||
throw new RuntimeException("Unexpected eval class (" + eval.getClass().getName() + ")");
|
throw new RuntimeException("Unexpected eval class (" + eval.getClass().getName() + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setupReferencedWorkbooks(Map<String, FormulaEvaluator> evaluators) {
|
|
||||||
CollaboratingWorkbooksEnvironment.setupFormulaEvaluator(evaluators);
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorkbookEvaluator _getWorkbookEvaluator() {
|
|
||||||
return _bookEvaluator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
|
||||||
public void setIgnoreMissingWorkbooks(boolean ignore){
|
|
||||||
_bookEvaluator.setIgnoreMissingWorkbooks(ignore);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
|
||||||
public void setDebugEvaluationOutputForNextEval(boolean value){
|
|
||||||
_bookEvaluator.setDebugEvaluationOutputForNextEval(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
package org.apache.poi.xssf.usermodel;
|
package org.apache.poi.xssf.usermodel;
|
||||||
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
|
import org.apache.poi.ss.formula.BaseFormulaEvaluator;
|
||||||
import org.apache.poi.ss.formula.EvaluationCell;
|
import org.apache.poi.ss.formula.EvaluationCell;
|
||||||
import org.apache.poi.ss.formula.IStabilityClassifier;
|
import org.apache.poi.ss.formula.IStabilityClassifier;
|
||||||
import org.apache.poi.ss.formula.WorkbookEvaluator;
|
import org.apache.poi.ss.formula.WorkbookEvaluator;
|
||||||
@ -88,7 +88,7 @@ public final class XSSFFormulaEvaluator extends BaseXSSFFormulaEvaluator {
|
|||||||
* cells, and calling evaluateFormulaCell on each one.
|
* cells, and calling evaluateFormulaCell on each one.
|
||||||
*/
|
*/
|
||||||
public static void evaluateAllFormulaCells(XSSFWorkbook wb) {
|
public static void evaluateAllFormulaCells(XSSFWorkbook wb) {
|
||||||
HSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
|
BaseFormulaEvaluator.evaluateAllFormulaCells(wb);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Loops over all cells in all sheets of the supplied
|
* Loops over all cells in all sheets of the supplied
|
||||||
@ -102,7 +102,7 @@ public final class XSSFFormulaEvaluator extends BaseXSSFFormulaEvaluator {
|
|||||||
* cells, and calling evaluateFormulaCell on each one.
|
* cells, and calling evaluateFormulaCell on each one.
|
||||||
*/
|
*/
|
||||||
public void evaluateAll() {
|
public void evaluateAll() {
|
||||||
HSSFFormulaEvaluator.evaluateAllFormulaCells(_book);
|
evaluateAllFormulaCells(_book, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -173,8 +173,19 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
|
|||||||
evaluator.evaluate(c);
|
evaluator.evaluate(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// And evaluate the other way too
|
||||||
|
evaluator.evaluateAll();
|
||||||
|
|
||||||
// Evaluate and check results
|
// Static evaluator won't work, as no references passed in
|
||||||
|
try {
|
||||||
|
XSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
|
||||||
|
fail("Static method lacks references, shouldn't work");
|
||||||
|
} catch(Exception e) {
|
||||||
|
// expected here
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Evaluate specific cells and check results
|
||||||
assertEquals("\"Hello!\"", evaluator.evaluate(cXSLX_cell).formatAsString());
|
assertEquals("\"Hello!\"", evaluator.evaluate(cXSLX_cell).formatAsString());
|
||||||
assertEquals("\"Test A1\"", evaluator.evaluate(cXSLX_sNR).formatAsString());
|
assertEquals("\"Test A1\"", evaluator.evaluate(cXSLX_sNR).formatAsString());
|
||||||
assertEquals("142.0", evaluator.evaluate(cXSLX_gNR).formatAsString());
|
assertEquals("142.0", evaluator.evaluate(cXSLX_gNR).formatAsString());
|
||||||
|
Loading…
Reference in New Issue
Block a user