2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 package org
.apache
.poi
.hssf
.usermodel
;
20 import java
.lang
.reflect
.Constructor
;
21 import java
.util
.HashMap
;
23 import java
.util
.Stack
;
25 import org
.apache
.poi
.hssf
.model
.FormulaParser
;
26 import org
.apache
.poi
.hssf
.model
.Workbook
;
27 import org
.apache
.poi
.hssf
.record
.formula
.Area3DPtg
;
28 import org
.apache
.poi
.hssf
.record
.formula
.AreaPtg
;
29 import org
.apache
.poi
.hssf
.record
.formula
.AttrPtg
;
30 import org
.apache
.poi
.hssf
.record
.formula
.BoolPtg
;
31 import org
.apache
.poi
.hssf
.record
.formula
.ControlPtg
;
32 import org
.apache
.poi
.hssf
.record
.formula
.IntPtg
;
33 import org
.apache
.poi
.hssf
.record
.formula
.MemErrPtg
;
34 import org
.apache
.poi
.hssf
.record
.formula
.MissingArgPtg
;
35 import org
.apache
.poi
.hssf
.record
.formula
.NamePtg
;
36 import org
.apache
.poi
.hssf
.record
.formula
.NameXPtg
;
37 import org
.apache
.poi
.hssf
.record
.formula
.NumberPtg
;
38 import org
.apache
.poi
.hssf
.record
.formula
.OperationPtg
;
39 import org
.apache
.poi
.hssf
.record
.formula
.ParenthesisPtg
;
40 import org
.apache
.poi
.hssf
.record
.formula
.Ptg
;
41 import org
.apache
.poi
.hssf
.record
.formula
.Ref3DPtg
;
42 import org
.apache
.poi
.hssf
.record
.formula
.ReferencePtg
;
43 import org
.apache
.poi
.hssf
.record
.formula
.StringPtg
;
44 import org
.apache
.poi
.hssf
.record
.formula
.UnionPtg
;
45 import org
.apache
.poi
.hssf
.record
.formula
.UnknownPtg
;
46 import org
.apache
.poi
.hssf
.record
.formula
.eval
.Area2DEval
;
47 import org
.apache
.poi
.hssf
.record
.formula
.eval
.Area3DEval
;
48 import org
.apache
.poi
.hssf
.record
.formula
.eval
.AreaEval
;
49 import org
.apache
.poi
.hssf
.record
.formula
.eval
.BlankEval
;
50 import org
.apache
.poi
.hssf
.record
.formula
.eval
.BoolEval
;
51 import org
.apache
.poi
.hssf
.record
.formula
.eval
.ErrorEval
;
52 import org
.apache
.poi
.hssf
.record
.formula
.eval
.Eval
;
53 import org
.apache
.poi
.hssf
.record
.formula
.eval
.FunctionEval
;
54 import org
.apache
.poi
.hssf
.record
.formula
.eval
.NameEval
;
55 import org
.apache
.poi
.hssf
.record
.formula
.eval
.NumberEval
;
56 import org
.apache
.poi
.hssf
.record
.formula
.eval
.OperationEval
;
57 import org
.apache
.poi
.hssf
.record
.formula
.eval
.Ref2DEval
;
58 import org
.apache
.poi
.hssf
.record
.formula
.eval
.Ref3DEval
;
59 import org
.apache
.poi
.hssf
.record
.formula
.eval
.RefEval
;
60 import org
.apache
.poi
.hssf
.record
.formula
.eval
.StringEval
;
61 import org
.apache
.poi
.hssf
.record
.formula
.eval
.ValueEval
;
64 * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
67 public class HSSFFormulaEvaluator
{
69 // params to lookup the right constructor using reflection
70 private static final Class
[] VALUE_CONTRUCTOR_CLASS_ARRAY
= new Class
[] { Ptg
.class };
72 private static final Class
[] AREA3D_CONSTRUCTOR_CLASS_ARRAY
= new Class
[] { Ptg
.class, ValueEval
[].class };
74 private static final Class
[] REFERENCE_CONSTRUCTOR_CLASS_ARRAY
= new Class
[] { Ptg
.class, ValueEval
.class };
76 private static final Class
[] REF3D_CONSTRUCTOR_CLASS_ARRAY
= new Class
[] { Ptg
.class, ValueEval
.class };
78 // Maps for mapping *Eval to *Ptg
79 private static final Map VALUE_EVALS_MAP
= new HashMap();
82 * Following is the mapping between the Ptg tokens returned
83 * by the FormulaParser and the *Eval classes that are used
84 * by the FormulaEvaluator
87 VALUE_EVALS_MAP
.put(BoolPtg
.class, BoolEval
.class);
88 VALUE_EVALS_MAP
.put(IntPtg
.class, NumberEval
.class);
89 VALUE_EVALS_MAP
.put(NumberPtg
.class, NumberEval
.class);
90 VALUE_EVALS_MAP
.put(StringPtg
.class, StringEval
.class);
95 protected HSSFRow row
;
96 protected HSSFSheet sheet
;
97 protected HSSFWorkbook workbook
;
99 public HSSFFormulaEvaluator(HSSFSheet sheet
, HSSFWorkbook workbook
) {
101 this.workbook
= workbook
;
104 public void setCurrentRow(HSSFRow row
) {
110 * Returns an underlying FormulaParser, for the specified
111 * Formula String and HSSFWorkbook.
112 * This will allow you to generate the Ptgs yourself, if
113 * your needs are more complex than just having the
116 public static FormulaParser
getUnderlyingParser(HSSFWorkbook workbook
, String formula
) {
117 return new FormulaParser(formula
, workbook
.getWorkbook());
121 * If cell contains a formula, the formula is evaluated and returned,
122 * else the CellValue simply copies the appropriate cell value from
123 * the cell and also its cell type. This method should be preferred over
124 * evaluateInCell() when the call should not modify the contents of the
128 public CellValue
evaluate(HSSFCell cell
) {
129 CellValue retval
= null;
131 switch (cell
.getCellType()) {
132 case HSSFCell
.CELL_TYPE_BLANK
:
133 retval
= new CellValue(HSSFCell
.CELL_TYPE_BLANK
);
135 case HSSFCell
.CELL_TYPE_BOOLEAN
:
136 retval
= new CellValue(HSSFCell
.CELL_TYPE_BOOLEAN
);
137 retval
.setBooleanValue(cell
.getBooleanCellValue());
139 case HSSFCell
.CELL_TYPE_ERROR
:
140 retval
= new CellValue(HSSFCell
.CELL_TYPE_ERROR
);
141 retval
.setErrorValue(cell
.getErrorCellValue());
143 case HSSFCell
.CELL_TYPE_FORMULA
:
144 retval
= getCellValueForEval(internalEvaluate(cell
, row
, sheet
, workbook
));
146 case HSSFCell
.CELL_TYPE_NUMERIC
:
147 retval
= new CellValue(HSSFCell
.CELL_TYPE_NUMERIC
);
148 retval
.setNumberValue(cell
.getNumericCellValue());
150 case HSSFCell
.CELL_TYPE_STRING
:
151 retval
= new CellValue(HSSFCell
.CELL_TYPE_STRING
);
152 retval
.setRichTextStringValue(cell
.getRichStringCellValue());
161 * If cell contains formula, it evaluates the formula,
162 * and saves the result of the formula. The cell
163 * remains as a formula cell.
164 * Else if cell does not contain formula, this method leaves
165 * the cell unchanged.
166 * Note that the type of the formula result is returned,
167 * so you know what kind of value is also stored with
170 * int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
172 * Be aware that your cell will hold both the formula,
173 * and the result. If you want the cell replaced with
174 * the result of the formula, use {@link #evaluateInCell(HSSFCell)}
175 * @param cell The cell to evaluate
176 * @return The type of the formula result (the cell's type remains as HSSFCell.CELL_TYPE_FORMULA however)
178 public int evaluateFormulaCell(HSSFCell cell
) {
180 switch (cell
.getCellType()) {
181 case HSSFCell
.CELL_TYPE_FORMULA
:
182 CellValue cv
= getCellValueForEval(internalEvaluate(cell
, row
, sheet
, workbook
));
183 switch (cv
.getCellType()) {
184 case HSSFCell
.CELL_TYPE_BOOLEAN
:
185 cell
.setCellValue(cv
.getBooleanValue());
187 case HSSFCell
.CELL_TYPE_ERROR
:
188 cell
.setCellValue(cv
.getErrorValue());
190 case HSSFCell
.CELL_TYPE_NUMERIC
:
191 cell
.setCellValue(cv
.getNumberValue());
193 case HSSFCell
.CELL_TYPE_STRING
:
194 cell
.setCellValue(cv
.getRichTextStringValue());
196 case HSSFCell
.CELL_TYPE_BLANK
:
198 case HSSFCell
.CELL_TYPE_FORMULA
: // this will never happen, we have already evaluated the formula
201 return cv
.getCellType();
208 * If cell contains formula, it evaluates the formula, and
209 * puts the formula result back into the cell, in place
210 * of the old formula.
211 * Else if cell does not contain formula, this method leaves
212 * the cell unchanged.
213 * Note that the same instance of HSSFCell is returned to
214 * allow chained calls like:
216 * int evaluatedCellType = evaluator.evaluateInCell(cell).getCellType();
218 * Be aware that your cell value will be changed to hold the
219 * result of the formula. If you simply want the formula
220 * value computed for you, use {@link #evaluateFormulaCell(HSSFCell)}
223 public HSSFCell
evaluateInCell(HSSFCell cell
) {
225 switch (cell
.getCellType()) {
226 case HSSFCell
.CELL_TYPE_FORMULA
:
227 CellValue cv
= getCellValueForEval(internalEvaluate(cell
, row
, sheet
, workbook
));
228 switch (cv
.getCellType()) {
229 case HSSFCell
.CELL_TYPE_BOOLEAN
:
230 cell
.setCellType(HSSFCell
.CELL_TYPE_BOOLEAN
);
231 cell
.setCellValue(cv
.getBooleanValue());
233 case HSSFCell
.CELL_TYPE_ERROR
:
234 cell
.setCellType(HSSFCell
.CELL_TYPE_ERROR
);
235 cell
.setCellValue(cv
.getErrorValue());
237 case HSSFCell
.CELL_TYPE_NUMERIC
:
238 cell
.setCellType(HSSFCell
.CELL_TYPE_NUMERIC
);
239 cell
.setCellValue(cv
.getNumberValue());
241 case HSSFCell
.CELL_TYPE_STRING
:
242 cell
.setCellType(HSSFCell
.CELL_TYPE_STRING
);
243 cell
.setCellValue(cv
.getRichTextStringValue());
245 case HSSFCell
.CELL_TYPE_BLANK
:
247 case HSSFCell
.CELL_TYPE_FORMULA
: // this will never happen, we have already evaluated the formula
257 * Returns a CellValue wrapper around the supplied ValueEval instance.
260 protected static CellValue
getCellValueForEval(ValueEval eval
) {
261 CellValue retval
= null;
263 if (eval
instanceof NumberEval
) {
264 NumberEval ne
= (NumberEval
) eval
;
265 retval
= new CellValue(HSSFCell
.CELL_TYPE_NUMERIC
);
266 retval
.setNumberValue(ne
.getNumberValue());
268 else if (eval
instanceof BoolEval
) {
269 BoolEval be
= (BoolEval
) eval
;
270 retval
= new CellValue(HSSFCell
.CELL_TYPE_BOOLEAN
);
271 retval
.setBooleanValue(be
.getBooleanValue());
273 else if (eval
instanceof StringEval
) {
274 StringEval ne
= (StringEval
) eval
;
275 retval
= new CellValue(HSSFCell
.CELL_TYPE_STRING
);
276 retval
.setStringValue(ne
.getStringValue());
278 else if (eval
instanceof BlankEval
) {
279 retval
= new CellValue(HSSFCell
.CELL_TYPE_BLANK
);
281 else if (eval
instanceof ErrorEval
) {
282 retval
= new CellValue(HSSFCell
.CELL_TYPE_ERROR
);
283 retval
.setErrorValue((byte)((ErrorEval
)eval
).getErrorCode());
284 // retval.setRichTextStringValue(new HSSFRichTextString("#An error occurred. check cell.getErrorCode()"));
287 retval
= new CellValue(HSSFCell
.CELL_TYPE_ERROR
);
294 * Dev. Note: Internal evaluate must be passed only a formula cell
295 * else a runtime exception will be thrown somewhere inside the method.
296 * (Hence this is a private method.)
298 private static ValueEval
internalEvaluate(HSSFCell srcCell
, HSSFRow srcRow
, HSSFSheet sheet
, HSSFWorkbook workbook
) {
299 int srcRowNum
= srcRow
.getRowNum();
300 short srcColNum
= srcCell
.getCellNum();
303 EvaluationCycleDetector tracker
= EvaluationCycleDetectorManager
.getTracker();
305 if(!tracker
.startEvaluate(workbook
, sheet
, srcRowNum
, srcColNum
)) {
306 return ErrorEval
.CIRCULAR_REF_ERROR
;
309 return evaluateCell(workbook
, sheet
, srcRowNum
, srcColNum
, srcCell
.getCellFormula());
311 tracker
.endEvaluate(workbook
, sheet
, srcRowNum
, srcColNum
);
314 private static ValueEval
evaluateCell(HSSFWorkbook workbook
, HSSFSheet sheet
,
315 int srcRowNum
, short srcColNum
, String cellFormulaText
) {
316 FormulaParser parser
= new FormulaParser(cellFormulaText
, workbook
.getWorkbook());
318 Ptg
[] ptgs
= parser
.getRPNPtg();
319 // -- parsing over --
322 Stack stack
= new Stack();
323 for (int i
= 0, iSize
= ptgs
.length
; i
< iSize
; i
++) {
325 // since we don't know how to handle these yet :(
327 if (ptg
instanceof ControlPtg
) { continue; }
328 if (ptg
instanceof MemErrPtg
) { continue; }
329 if (ptg
instanceof MissingArgPtg
) { continue; }
330 if (ptg
instanceof NamePtg
) {
331 // named ranges, macro functions
332 NamePtg namePtg
= (NamePtg
) ptg
;
333 stack
.push(new NameEval(namePtg
.getIndex()));
336 if (ptg
instanceof NameXPtg
) {
337 // TODO - external functions
340 if (ptg
instanceof UnknownPtg
) { continue; }
342 if (ptg
instanceof OperationPtg
) {
343 OperationPtg optg
= (OperationPtg
) ptg
;
345 // parens can be ignored since we have RPN tokens
346 if (optg
instanceof ParenthesisPtg
) { continue; }
347 if (optg
instanceof AttrPtg
) { continue; }
348 if (optg
instanceof UnionPtg
) { continue; }
350 OperationEval operation
= OperationEvaluatorFactory
.create(optg
);
352 int numops
= operation
.getNumberOfOperands();
353 Eval
[] ops
= new Eval
[numops
];
355 // storing the ops in reverse order since they are popping
356 for (int j
= numops
- 1; j
>= 0; j
--) {
357 Eval p
= (Eval
) stack
.pop();
360 Eval opresult
= invokeOperation(operation
, ops
, srcRowNum
, srcColNum
, workbook
, sheet
);
361 stack
.push(opresult
);
363 else if (ptg
instanceof ReferencePtg
) {
364 ReferencePtg refPtg
= (ReferencePtg
) ptg
;
365 int colIx
= refPtg
.getColumn();
366 int rowIx
= refPtg
.getRow();
367 HSSFRow row
= sheet
.getRow(rowIx
);
368 HSSFCell cell
= (row
!= null) ? row
.getCell(colIx
) : null;
369 stack
.push(createRef2DEval(refPtg
, cell
, row
, sheet
, workbook
));
371 else if (ptg
instanceof Ref3DPtg
) {
372 Ref3DPtg refPtg
= (Ref3DPtg
) ptg
;
373 int colIx
= refPtg
.getColumn();
374 int rowIx
= refPtg
.getRow();
375 Workbook wb
= workbook
.getWorkbook();
376 HSSFSheet xsheet
= workbook
.getSheetAt(wb
.getSheetIndexFromExternSheetIndex(refPtg
.getExternSheetIndex()));
377 HSSFRow row
= xsheet
.getRow(rowIx
);
378 HSSFCell cell
= (row
!= null) ? row
.getCell(colIx
) : null;
379 stack
.push(createRef3DEval(refPtg
, cell
, row
, xsheet
, workbook
));
381 else if (ptg
instanceof AreaPtg
) {
382 AreaPtg ap
= (AreaPtg
) ptg
;
383 AreaEval ae
= evaluateAreaPtg(sheet
, workbook
, ap
);
386 else if (ptg
instanceof Area3DPtg
) {
387 Area3DPtg a3dp
= (Area3DPtg
) ptg
;
388 AreaEval ae
= evaluateArea3dPtg(workbook
, a3dp
);
392 Eval ptgEval
= getEvalForPtg(ptg
);
397 ValueEval value
= ((ValueEval
) stack
.pop());
398 if (!stack
.isEmpty()) {
399 throw new IllegalStateException("evaluation stack not empty");
401 value
= dereferenceValue(value
, srcRowNum
, srcColNum
);
402 if (value
instanceof BlankEval
) {
403 // Note Excel behaviour here. A blank final final value is converted to zero.
404 return NumberEval
.ZERO
;
405 // Formulas _never_ evaluate to blank. If a formula appears to have evaluated to
406 // blank, the actual value is empty string. This can be verified with ISBLANK().
412 * Dereferences a single value from any AreaEval or RefEval evaluation result.
413 * If the supplied evaluationResult is just a plain value, it is returned as-is.
414 * @return a <tt>NumberEval</tt>, <tt>StringEval</tt>, <tt>BoolEval</tt>,
415 * <tt>BlankEval</tt> or <tt>ErrorEval</tt>. Never <code>null</code>.
417 private static ValueEval
dereferenceValue(ValueEval evaluationResult
, int srcRowNum
, short srcColNum
) {
418 if (evaluationResult
instanceof RefEval
) {
419 RefEval rv
= (RefEval
) evaluationResult
;
420 return rv
.getInnerValueEval();
422 if (evaluationResult
instanceof AreaEval
) {
423 AreaEval ae
= (AreaEval
) evaluationResult
;
426 return ae
.getValues()[0];
428 return ae
.getValueAt(ae
.getFirstRow(), srcColNum
);
431 return ae
.getValueAt(srcRowNum
, ae
.getFirstColumn());
433 return ErrorEval
.VALUE_INVALID
;
435 return evaluationResult
;
438 private static Eval
invokeOperation(OperationEval operation
, Eval
[] ops
, int srcRowNum
, short srcColNum
,
439 HSSFWorkbook workbook
, HSSFSheet sheet
) {
441 if(operation
instanceof FunctionEval
) {
442 FunctionEval fe
= (FunctionEval
) operation
;
443 if(fe
.isFreeRefFunction()) {
444 return fe
.getFreeRefFunction().evaluate(ops
, srcRowNum
, srcColNum
, workbook
, sheet
);
447 return operation
.evaluate(ops
, srcRowNum
, srcColNum
);
450 public static AreaEval
evaluateAreaPtg(HSSFSheet sheet
, HSSFWorkbook workbook
, AreaPtg ap
) {
451 int row0
= ap
.getFirstRow();
452 int col0
= ap
.getFirstColumn();
453 int row1
= ap
.getLastRow();
454 int col1
= ap
.getLastColumn();
456 // If the last row is -1, then the
457 // reference is for the rest of the column
459 // TODO: Handle whole column ranges properly
460 if(row1
== -1 && row0
>= 0) {
461 row1
= (short)sheet
.getLastRowNum();
463 ValueEval
[] values
= evalArea(workbook
, sheet
, row0
, col0
, row1
, col1
);
464 return new Area2DEval(ap
, values
);
467 public static AreaEval
evaluateArea3dPtg(HSSFWorkbook workbook
, Area3DPtg a3dp
) {
468 int row0
= a3dp
.getFirstRow();
469 int col0
= a3dp
.getFirstColumn();
470 int row1
= a3dp
.getLastRow();
471 int col1
= a3dp
.getLastColumn();
472 Workbook wb
= workbook
.getWorkbook();
473 HSSFSheet xsheet
= workbook
.getSheetAt(wb
.getSheetIndexFromExternSheetIndex(a3dp
.getExternSheetIndex()));
475 // If the last row is -1, then the
476 // reference is for the rest of the column
478 // TODO: Handle whole column ranges properly
479 if(row1
== -1 && row0
>= 0) {
480 row1
= (short)xsheet
.getLastRowNum();
483 ValueEval
[] values
= evalArea(workbook
, xsheet
, row0
, col0
, row1
, col1
);
484 return new Area3DEval(a3dp
, values
);
487 private static ValueEval
[] evalArea(HSSFWorkbook workbook
, HSSFSheet sheet
,
488 int row0
, int col0
, int row1
, int col1
) {
489 ValueEval
[] values
= new ValueEval
[(row1
- row0
+ 1) * (col1
- col0
+ 1)];
490 for (int x
= row0
; sheet
!= null && x
< row1
+ 1; x
++) {
491 HSSFRow row
= sheet
.getRow(x
);
492 for (int y
= col0
; y
< col1
+ 1; y
++) {
495 cellEval
= BlankEval
.INSTANCE
;
497 cellEval
= getEvalForCell(row
.getCell(y
), row
, sheet
, workbook
);
499 values
[(x
- row0
) * (col1
- col0
+ 1) + (y
- col0
)] = cellEval
;
506 * returns an appropriate Eval impl instance for the Ptg. The Ptg must be
507 * one of: Area3DPtg, AreaPtg, ReferencePtg, Ref3DPtg, IntPtg, NumberPtg,
508 * StringPtg, BoolPtg <br/>special Note: OperationPtg subtypes cannot be
513 protected static Eval
getEvalForPtg(Ptg ptg
) {
516 Class clazz
= (Class
) VALUE_EVALS_MAP
.get(ptg
.getClass());
518 if (ptg
instanceof Area3DPtg
) {
519 Constructor constructor
= clazz
.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY
);
520 retval
= (OperationEval
) constructor
.newInstance(new Ptg
[] { ptg
});
522 else if (ptg
instanceof AreaPtg
) {
523 Constructor constructor
= clazz
.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY
);
524 retval
= (OperationEval
) constructor
.newInstance(new Ptg
[] { ptg
});
526 else if (ptg
instanceof ReferencePtg
) {
527 Constructor constructor
= clazz
.getConstructor(REFERENCE_CONSTRUCTOR_CLASS_ARRAY
);
528 retval
= (OperationEval
) constructor
.newInstance(new Ptg
[] { ptg
});
530 else if (ptg
instanceof Ref3DPtg
) {
531 Constructor constructor
= clazz
.getConstructor(REF3D_CONSTRUCTOR_CLASS_ARRAY
);
532 retval
= (OperationEval
) constructor
.newInstance(new Ptg
[] { ptg
});
535 if (ptg
instanceof IntPtg
|| ptg
instanceof NumberPtg
|| ptg
instanceof StringPtg
536 || ptg
instanceof BoolPtg
) {
537 Constructor constructor
= clazz
.getConstructor(VALUE_CONTRUCTOR_CLASS_ARRAY
);
538 retval
= (ValueEval
) constructor
.newInstance(new Ptg
[] { ptg
});
542 catch (Exception e
) {
543 throw new RuntimeException("Fatal Error: ", e
);
550 * Given a cell, find its type and from that create an appropriate ValueEval
551 * impl instance and return that. Since the cell could be an external
552 * reference, we need the sheet that this belongs to.
553 * Non existent cells are treated as empty.
558 protected static ValueEval
getEvalForCell(HSSFCell cell
, HSSFRow row
, HSSFSheet sheet
, HSSFWorkbook workbook
) {
561 return BlankEval
.INSTANCE
;
563 switch (cell
.getCellType()) {
564 case HSSFCell
.CELL_TYPE_NUMERIC
:
565 return new NumberEval(cell
.getNumericCellValue());
566 case HSSFCell
.CELL_TYPE_STRING
:
567 return new StringEval(cell
.getRichStringCellValue().getString());
568 case HSSFCell
.CELL_TYPE_FORMULA
:
569 return internalEvaluate(cell
, row
, sheet
, workbook
);
570 case HSSFCell
.CELL_TYPE_BOOLEAN
:
571 return BoolEval
.valueOf(cell
.getBooleanCellValue());
572 case HSSFCell
.CELL_TYPE_BLANK
:
573 return BlankEval
.INSTANCE
;
574 case HSSFCell
.CELL_TYPE_ERROR
:
575 return ErrorEval
.valueOf(cell
.getErrorCellValue());
577 throw new RuntimeException("Unexpected cell type (" + cell
.getCellType() + ")");
581 * Creates a Ref2DEval for ReferencePtg.
582 * Non existent cells are treated as RefEvals containing BlankEval.
584 private static Ref2DEval
createRef2DEval(ReferencePtg ptg
, HSSFCell cell
,
585 HSSFRow row
, HSSFSheet sheet
, HSSFWorkbook workbook
) {
587 return new Ref2DEval(ptg
, BlankEval
.INSTANCE
);
590 switch (cell
.getCellType()) {
591 case HSSFCell
.CELL_TYPE_NUMERIC
:
592 return new Ref2DEval(ptg
, new NumberEval(cell
.getNumericCellValue()));
593 case HSSFCell
.CELL_TYPE_STRING
:
594 return new Ref2DEval(ptg
, new StringEval(cell
.getRichStringCellValue().getString()));
595 case HSSFCell
.CELL_TYPE_FORMULA
:
596 return new Ref2DEval(ptg
, internalEvaluate(cell
, row
, sheet
, workbook
));
597 case HSSFCell
.CELL_TYPE_BOOLEAN
:
598 return new Ref2DEval(ptg
, BoolEval
.valueOf(cell
.getBooleanCellValue()));
599 case HSSFCell
.CELL_TYPE_BLANK
:
600 return new Ref2DEval(ptg
, BlankEval
.INSTANCE
);
601 case HSSFCell
.CELL_TYPE_ERROR
:
602 return new Ref2DEval(ptg
, ErrorEval
.valueOf(cell
.getErrorCellValue()));
604 throw new RuntimeException("Unexpected cell type (" + cell
.getCellType() + ")");
608 * create a Ref3DEval for Ref3DPtg.
610 private static Ref3DEval
createRef3DEval(Ref3DPtg ptg
, HSSFCell cell
,
611 HSSFRow row
, HSSFSheet sheet
, HSSFWorkbook workbook
) {
613 return new Ref3DEval(ptg
, BlankEval
.INSTANCE
);
615 switch (cell
.getCellType()) {
616 case HSSFCell
.CELL_TYPE_NUMERIC
:
617 return new Ref3DEval(ptg
, new NumberEval(cell
.getNumericCellValue()));
618 case HSSFCell
.CELL_TYPE_STRING
:
619 return new Ref3DEval(ptg
, new StringEval(cell
.getRichStringCellValue().getString()));
620 case HSSFCell
.CELL_TYPE_FORMULA
:
621 return new Ref3DEval(ptg
, internalEvaluate(cell
, row
, sheet
, workbook
));
622 case HSSFCell
.CELL_TYPE_BOOLEAN
:
623 return new Ref3DEval(ptg
, BoolEval
.valueOf(cell
.getBooleanCellValue()));
624 case HSSFCell
.CELL_TYPE_BLANK
:
625 return new Ref3DEval(ptg
, BlankEval
.INSTANCE
);
626 case HSSFCell
.CELL_TYPE_ERROR
:
627 return new Ref3DEval(ptg
, ErrorEval
.valueOf(cell
.getErrorCellValue()));
629 throw new RuntimeException("Unexpected cell type (" + cell
.getCellType() + ")");
633 * Mimics the 'data view' of a cell. This allows formula evaluator
634 * to return a CellValue instead of precasting the value to String
635 * or Number or boolean type.
636 * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
638 public static final class CellValue
{
639 private int cellType
;
640 private HSSFRichTextString richTextStringValue
;
641 private double numberValue
;
642 private boolean booleanValue
;
643 private byte errorValue
;
646 * CellType should be one of the types defined in HSSFCell
649 public CellValue(int cellType
) {
651 this.cellType
= cellType
;
654 * @return Returns the booleanValue.
656 public boolean getBooleanValue() {
660 * @param booleanValue The booleanValue to set.
662 public void setBooleanValue(boolean booleanValue
) {
663 this.booleanValue
= booleanValue
;
666 * @return Returns the numberValue.
668 public double getNumberValue() {
672 * @param numberValue The numberValue to set.
674 public void setNumberValue(double numberValue
) {
675 this.numberValue
= numberValue
;
678 * @return Returns the stringValue. This method is deprecated, use
679 * getRichTextStringValue instead
682 public String
getStringValue() {
683 return richTextStringValue
.getString();
686 * @param stringValue The stringValue to set. This method is deprecated, use
687 * getRichTextStringValue instead.
690 public void setStringValue(String stringValue
) {
691 this.richTextStringValue
= new HSSFRichTextString(stringValue
);
694 * @return Returns the cellType.
696 public int getCellType() {
700 * @return Returns the errorValue.
702 public byte getErrorValue() {
706 * @param errorValue The errorValue to set.
708 public void setErrorValue(byte errorValue
) {
709 this.errorValue
= errorValue
;
712 * @return Returns the richTextStringValue.
714 public HSSFRichTextString
getRichTextStringValue() {
715 return richTextStringValue
;
718 * @param richTextStringValue The richTextStringValue to set.
720 public void setRichTextStringValue(HSSFRichTextString richTextStringValue
) {
721 this.richTextStringValue
= richTextStringValue
;
732 void inspectPtgs(String formula
) {
733 FormulaParser fp
= new FormulaParser(formula
, workbook
.getWorkbook());
735 Ptg
[] ptgs
= fp
.getRPNPtg();
736 System
.out
.println("<ptg-group>");
737 for (int i
= 0, iSize
= ptgs
.length
; i
< iSize
; i
++) {
738 System
.out
.println("<ptg>");
739 System
.out
.println(ptgs
[i
]);
740 if (ptgs
[i
] instanceof OperationPtg
) {
741 System
.out
.println("numoperands: " + ((OperationPtg
) ptgs
[i
]).getNumberOfOperands());
743 System
.out
.println("</ptg>");
745 System
.out
.println("</ptg-group>");