Apply, with a few tweaks, the patch from bug #48996 - initial support for External Name References in HSSF formula evaluation

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@953395 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2010-06-10 17:07:06 +00:00
parent bf4e6ff464
commit e92c009814
16 changed files with 318 additions and 12 deletions

View File

@ -34,6 +34,7 @@
<changes> <changes>
<release version="3.7-SNAPSHOT" date="2010-??-??"> <release version="3.7-SNAPSHOT" date="2010-??-??">
<action dev="POI-DEVELOPERS" type="add">48996 - initial support for External Name References in HSSF formula evaluation</action>
<action dev="POI-DEVELOPERS" type="fix">46664 - fix up Tab IDs when adding new sheets, so that print areas don't end up invalid</action> <action dev="POI-DEVELOPERS" type="fix">46664 - fix up Tab IDs when adding new sheets, so that print areas don't end up invalid</action>
<action dev="POI-DEVELOPERS" type="fix">45269 - improve replaceText on HWPF ranges</action> <action dev="POI-DEVELOPERS" type="fix">45269 - improve replaceText on HWPF ranges</action>
<action dev="POI-DEVELOPERS" type="fix">47815 - correct documentation on what happens when you request a String from a non-string Formula cell</action> <action dev="POI-DEVELOPERS" type="fix">47815 - correct documentation on what happens when you request a String from a non-string Formula cell</action>

View File

@ -162,6 +162,7 @@ public final class BiffViewer {
case ExtSSTRecord.sid: return new ExtSSTRecord(in); case ExtSSTRecord.sid: return new ExtSSTRecord(in);
case ExtendedFormatRecord.sid: return new ExtendedFormatRecord(in); case ExtendedFormatRecord.sid: return new ExtendedFormatRecord(in);
case ExternSheetRecord.sid: return new ExternSheetRecord(in); case ExternSheetRecord.sid: return new ExternSheetRecord(in);
case ExternalNameRecord.sid: return new ExternalNameRecord(in);
case FeatRecord.sid: return new FeatRecord(in); case FeatRecord.sid: return new FeatRecord(in);
case FeatHdrRecord.sid: return new FeatHdrRecord(in); case FeatHdrRecord.sid: return new FeatHdrRecord(in);
case FilePassRecord.sid: return new FilePassRecord(in); case FilePassRecord.sid: return new FilePassRecord(in);

View File

@ -81,6 +81,7 @@ import org.apache.poi.hssf.record.formula.NameXPtg;
import org.apache.poi.hssf.record.formula.FormulaShifter; import org.apache.poi.hssf.record.formula.FormulaShifter;
import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet; import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
@ -1771,6 +1772,14 @@ public final class InternalWorkbook {
} }
return new ExternalSheet(extNames[0], extNames[1]); return new ExternalSheet(extNames[0], extNames[1]);
} }
public ExternalName getExternalName(int externSheetIndex, int externNameIndex) {
String nameName = linkTable.resolveNameXText(externSheetIndex, externNameIndex);
if(nameName == null) {
return null;
}
int ix = linkTable.resolveNameXIx(externSheetIndex, externNameIndex);
return new ExternalName(nameName, externNameIndex, ix);
}
/** /**
* Finds the sheet index for a particular external sheet number. * Finds the sheet index for a particular external sheet number.

View File

@ -125,6 +125,10 @@ final class LinkTable {
return _externalNameRecords[definedNameIndex].getText(); return _externalNameRecords[definedNameIndex].getText();
} }
public int getNameIx(int definedNameIndex) {
return _externalNameRecords[definedNameIndex].getIx();
}
/** /**
* Performs case-insensitive search * Performs case-insensitive search
* @return -1 if not found * @return -1 if not found
@ -316,8 +320,12 @@ final class LinkTable {
if (!ebr.isExternalReferences()) { if (!ebr.isExternalReferences()) {
return null; return null;
} }
// Sheet name only applies if not a global reference
int shIx = _externSheetRecord.getFirstSheetIndexFromRefIndex(extRefIndex); int shIx = _externSheetRecord.getFirstSheetIndexFromRefIndex(extRefIndex);
String usSheetName = ebr.getSheetNames()[shIx]; String usSheetName = null;
if(shIx >= 0) {
usSheetName = ebr.getSheetNames()[shIx];
}
return new String[] { return new String[] {
ebr.getURL(), ebr.getURL(),
usSheetName, usSheetName,
@ -419,6 +427,10 @@ final class LinkTable {
int extBookIndex = _externSheetRecord.getExtbookIndexFromRefIndex(refIndex); int extBookIndex = _externSheetRecord.getExtbookIndexFromRefIndex(refIndex);
return _externalBookBlocks[extBookIndex].getNameText(definedNameIndex); return _externalBookBlocks[extBookIndex].getNameText(definedNameIndex);
} }
public int resolveNameXIx(int refIndex, int definedNameIndex) {
int extBookIndex = _externSheetRecord.getExtbookIndexFromRefIndex(refIndex);
return _externalBookBlocks[extBookIndex].getNameIx(definedNameIndex);
}
public NameXPtg getNameXPtg(String name) { public NameXPtg getNameXPtg(String name) {
// first find any external book block that contains the name: // first find any external book block that contains the name:

View File

@ -41,7 +41,8 @@ public final class ExternalNameRecord extends StandardRecord {
private short field_1_option_flag; private short field_1_option_flag;
private int field_2_not_used; private short field_2_ixals;
private short field_3_not_used;
private String field_4_name; private String field_4_name;
private Formula field_5_name_definition; private Formula field_5_name_definition;
@ -97,6 +98,16 @@ public final class ExternalNameRecord extends StandardRecord {
return field_4_name; return field_4_name;
} }
/**
* If this is a local name, then this is the (1 based)
* index of the name of the Sheet this refers to, as
* defined in the preceeding {@link SupBookRecord}.
* If it isn't a local name, then it must be zero.
*/
public short getIx() {
return field_2_ixals;
}
protected int getDataSize(){ protected int getDataSize(){
int result = 2 + 4; // short and int int result = 2 + 4; // short and int
result += StringUtil.getEncodedSize(field_4_name) - 1; //size is byte, not short result += StringUtil.getEncodedSize(field_4_name) - 1; //size is byte, not short
@ -114,10 +125,11 @@ public final class ExternalNameRecord extends StandardRecord {
public void serialize(LittleEndianOutput out) { public void serialize(LittleEndianOutput out) {
out.writeShort(field_1_option_flag); out.writeShort(field_1_option_flag);
out.writeInt(field_2_not_used); out.writeShort(field_2_ixals);
out.writeShort(field_3_not_used);
out.writeByte(field_4_name.length()); out.writeByte(field_4_name.length());
StringUtil.writeUnicodeStringFlagAndData(out, field_4_name); StringUtil.writeUnicodeStringFlagAndData(out, field_4_name);
if(!isOLELink() && !isStdDocumentNameIdentifier()){ if(!isOLELink() && !isStdDocumentNameIdentifier()){
if(isAutomaticLink()){ if(isAutomaticLink()){
@ -133,7 +145,8 @@ public final class ExternalNameRecord extends StandardRecord {
public ExternalNameRecord(RecordInputStream in) { public ExternalNameRecord(RecordInputStream in) {
field_1_option_flag = in.readShort(); field_1_option_flag = in.readShort();
field_2_not_used = in.readInt(); field_2_ixals = in.readShort();
field_3_not_used = in.readShort();
int numChars = in.readUByte(); int numChars = in.readUByte();
field_4_name = StringUtil.readUnicodeString(in, numChars); field_4_name = StringUtil.readUnicodeString(in, numChars);
@ -166,10 +179,13 @@ public final class ExternalNameRecord extends StandardRecord {
public String toString() { public String toString() {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
sb.append(getClass().getName()).append(" [EXTERNALNAME "); sb.append("[EXTERNALNAME]\n");
sb.append(" ").append(field_4_name); sb.append(" .ix = ").append(field_2_ixals).append("\n");
sb.append(" ix=").append(field_2_not_used); sb.append(" .name = ").append(field_4_name).append("\n");
sb.append("]"); if(field_5_name_definition != null) {
sb.append(" .formula = ").append(field_5_name_definition).append("\n");
}
sb.append("[/EXTERNALNAME]\n");
return sb.toString(); return sb.toString();
} }
} }

View File

@ -74,6 +74,12 @@ public final class NameXPtg extends OperandPtg implements WorkbookDependentFormu
throw new RuntimeException("3D references need a workbook to determine formula text"); throw new RuntimeException("3D references need a workbook to determine formula text");
} }
public String toString(){
String retValue = "NameXPtg:[sheetRefIndex:" + _sheetRefIndex +
" , nameNumber:" + _nameNumber + "]" ;
return retValue;
}
public byte getDefaultOperandClass() { public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE; return Ptg.CLASS_VALUE;
} }

View File

@ -33,6 +33,7 @@ import org.apache.poi.ss.formula.FormulaParseException;
import org.apache.poi.ss.formula.FormulaParsingWorkbook; import org.apache.poi.ss.formula.FormulaParsingWorkbook;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook; import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
import org.apache.poi.ss.formula.FormulaType; import org.apache.poi.ss.formula.FormulaType;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName;
/** /**
* Internal POI use only * Internal POI use only
@ -108,6 +109,10 @@ public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
return _iBook.getExternalSheet(externSheetIndex); return _iBook.getExternalSheet(externSheetIndex);
} }
public ExternalName getExternalName(int externSheetIndex, int externNameIndex) {
return _iBook.getExternalName(externSheetIndex, externNameIndex);
}
public String resolveNameXText(NameXPtg n) { public String resolveNameXText(NameXPtg n) {
return _iBook.resolveNameXText(n.getSheetRefIndex(), n.getNameIndex()); return _iBook.resolveNameXText(n.getSheetRefIndex(), n.getNameIndex());
} }

View File

@ -47,6 +47,7 @@ public interface EvaluationWorkbook {
*/ */
ExternalSheet getExternalSheet(int externSheetIndex); ExternalSheet getExternalSheet(int externSheetIndex);
int convertFromExternSheetIndex(int externSheetIndex); int convertFromExternSheetIndex(int externSheetIndex);
ExternalName getExternalName(int externSheetIndex, int externNameIndex);
EvaluationName getName(NamePtg namePtg); EvaluationName getName(NamePtg namePtg);
String resolveNameXText(NameXPtg ptg); String resolveNameXText(NameXPtg ptg);
Ptg[] getFormulaTokens(EvaluationCell cell); Ptg[] getFormulaTokens(EvaluationCell cell);
@ -66,4 +67,24 @@ public interface EvaluationWorkbook {
return _sheetName; return _sheetName;
} }
} }
class ExternalName {
private final String _nameName;
private final int _nameNumber;
private final int _ix;
public ExternalName(String nameName, int nameNumber, int ix) {
_nameName = nameName;
_nameNumber = nameNumber;
_ix = ix;
}
public String getName() {
return _nameName;
}
public int getNumber() {
return _nameNumber;
}
public int getIx() {
return _ix;
}
}
} }

View File

@ -17,10 +17,15 @@
package org.apache.poi.ss.formula; package org.apache.poi.ss.formula;
import org.apache.poi.hssf.record.formula.Area3DPtg;
import org.apache.poi.hssf.record.formula.NameXPtg;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.eval.*; import org.apache.poi.hssf.record.formula.eval.*;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException; import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet; import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet;
import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.util.CellReference.NameType; import org.apache.poi.ss.util.CellReference.NameType;
@ -254,4 +259,40 @@ public final class OperationEvaluationContext {
SheetRefEvaluator sre = createExternSheetRefEvaluator(extSheetIndex); SheetRefEvaluator sre = createExternSheetRefEvaluator(extSheetIndex);
return new LazyAreaEval(firstRowIndex, firstColumnIndex, lastRowIndex, lastColumnIndex, sre); return new LazyAreaEval(firstRowIndex, firstColumnIndex, lastRowIndex, lastColumnIndex, sre);
} }
public ValueEval getNameXEval(NameXPtg nameXPtg) {
ExternalSheet externSheet = _workbook.getExternalSheet(nameXPtg.getSheetRefIndex());
if(externSheet == null)
return new NameXEval(nameXPtg);
String workbookName = externSheet.getWorkbookName();
ExternalName externName = _workbook.getExternalName(
nameXPtg.getSheetRefIndex(),
nameXPtg.getNameIndex()
);
try{
WorkbookEvaluator refWorkbookEvaluator = _bookEvaluator.getOtherWorkbookEvaluator(workbookName);
EvaluationName evaluationName = refWorkbookEvaluator.getName(externName.getName(),externName.getIx()-1);
if(evaluationName != null && evaluationName.hasFormula()){
if (evaluationName.getNameDefinition().length > 1) {
throw new RuntimeException("Complex name formulas not supported yet");
}
Ptg ptg = evaluationName.getNameDefinition()[0];
if(ptg instanceof Ref3DPtg){
Ref3DPtg ref3D = (Ref3DPtg)ptg;
int sheetIndex = refWorkbookEvaluator.getSheetIndexByExternIndex(ref3D.getExternSheetIndex());
String sheetName = refWorkbookEvaluator.getSheetName(sheetIndex);
SheetRefEvaluator sre = createExternSheetRefEvaluator(workbookName, sheetName);
return new LazyRefEval(ref3D.getRow(), ref3D.getColumn(), sre);
}else if(ptg instanceof Area3DPtg){
Area3DPtg area3D = (Area3DPtg)ptg;
int sheetIndex = refWorkbookEvaluator.getSheetIndexByExternIndex(area3D.getExternSheetIndex());
String sheetName = refWorkbookEvaluator.getSheetName(sheetIndex);
SheetRefEvaluator sre = createExternSheetRefEvaluator(workbookName, sheetName);
return new LazyAreaEval(area3D.getFirstRow(), area3D.getFirstColumn(), area3D.getLastRow(), area3D.getLastColumn(), sre);
}
}
return ErrorEval.REF_INVALID;
}catch(WorkbookNotFoundException wnfe){
return ErrorEval.REF_INVALID;
}
}
} }

View File

@ -65,6 +65,7 @@ import org.apache.poi.hssf.record.formula.functions.Choose;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
import org.apache.poi.hssf.record.formula.functions.IfFunc; import org.apache.poi.hssf.record.formula.functions.IfFunc;
import org.apache.poi.hssf.record.formula.udf.UDFFinder; import org.apache.poi.hssf.record.formula.udf.UDFFinder;
import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
import org.apache.poi.hssf.util.CellReference; import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException; import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException;
import org.apache.poi.ss.formula.eval.NotImplementedException; import org.apache.poi.ss.formula.eval.NotImplementedException;
@ -125,6 +126,19 @@ public final class WorkbookEvaluator {
return _workbook.getSheet(sheetIndex); return _workbook.getSheet(sheetIndex);
} }
/* package */ EvaluationName getName(String name, int sheetIndex) {
NamePtg namePtg = null;
if(_workbook instanceof HSSFEvaluationWorkbook){
namePtg =((HSSFEvaluationWorkbook)_workbook).getName(name, sheetIndex).createPtg();
}
if(namePtg == null) {
return null;
} else {
return _workbook.getName(namePtg);
}
}
private static boolean isDebugLogEnabled() { private static boolean isDebugLogEnabled() {
return false; return false;
} }
@ -224,6 +238,10 @@ public final class WorkbookEvaluator {
return result.intValue(); return result.intValue();
} }
/* package */ int getSheetIndexByExternIndex(int externSheetIndex) {
return _workbook.convertFromExternSheetIndex(externSheetIndex);
}
/** /**
* @return never <code>null</code>, never {@link BlankEval} * @return never <code>null</code>, never {@link BlankEval}
@ -524,7 +542,7 @@ public final class WorkbookEvaluator {
throw new RuntimeException("Don't now how to evalate name '" + nameRecord.getNameText() + "'"); throw new RuntimeException("Don't now how to evalate name '" + nameRecord.getNameText() + "'");
} }
if (ptg instanceof NameXPtg) { if (ptg instanceof NameXPtg) {
return new NameXEval(((NameXPtg) ptg)); return ec.getNameXEval(((NameXPtg) ptg));
} }
if (ptg instanceof IntPtg) { if (ptg instanceof IntPtg) {

View File

@ -107,6 +107,10 @@ final class ForkedEvaluationWorkbook implements EvaluationWorkbook {
return getSharedSheet(getSheetName(sheetIndex)); return getSharedSheet(getSheetName(sheetIndex));
} }
public ExternalName getExternalName(int externSheetIndex, int externNameIndex) {
return _masterBook.getExternalName(externSheetIndex, externNameIndex);
}
public int getSheetIndex(EvaluationSheet sheet) { public int getSheetIndex(EvaluationSheet sheet) {
if (sheet instanceof ForkedEvaluationSheet) { if (sheet instanceof ForkedEvaluationSheet) {
ForkedEvaluationSheet mes = (ForkedEvaluationSheet) sheet; ForkedEvaluationSheet mes = (ForkedEvaluationSheet) sheet;

View File

@ -29,6 +29,7 @@ import org.apache.poi.ss.formula.FormulaParser;
import org.apache.poi.ss.formula.FormulaParsingWorkbook; import org.apache.poi.ss.formula.FormulaParsingWorkbook;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook; import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
import org.apache.poi.ss.formula.FormulaType; import org.apache.poi.ss.formula.FormulaType;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;
/** /**
@ -95,6 +96,10 @@ public final class XSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
return _uBook.getSheetName(sheetIndex); return _uBook.getSheetName(sheetIndex);
} }
public ExternalName getExternalName(int externSheetIndex, int externNameIndex) {
throw new RuntimeException("Not implemented yet");
}
public NameXPtg getNameXPtg(String name) { public NameXPtg getNameXPtg(String name) {
// may require to return null to make tests pass // may require to return null to make tests pass
throw new RuntimeException("Not implemented yet"); throw new RuntimeException("Not implemented yet");

View File

@ -0,0 +1,106 @@
/* ====================================================================
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.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.CellReference;
/**
* Tests for proper calculation of named ranges from external workbooks.
*
*
* @author Stephen Wolke (smwolke at geistig.com)
*/
public final class TestExternalNameReference extends TestCase {
double MARKUP_COST = 1.9d;
double MARKUP_COST_1 = 1.8d;
double MARKUP_COST_2 = 1.5d;
double PART_COST = 12.3d;
double NEW_QUANT = 7.0d;
double NEW_PART_COST = 15.3d;
/**
* tests <tt>NameXPtg for external cell reference by name</tt> and logic in Workbook below that
*/
public void testReadCalcSheet() {
try{
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("XRefCalc.xls");
assertEquals("Sheet1!$A$2", wb.getName("QUANT").getRefersToFormula());
assertEquals("Sheet1!$B$2", wb.getName("PART").getRefersToFormula());
assertEquals("x123",wb.getSheet("Sheet1").getRow(1).getCell(1).getStringCellValue());
assertEquals("Sheet1!$C$2", wb.getName("UNITCOST").getRefersToFormula());
CellReference cellRef = new CellReference(wb.getName("UNITCOST").getRefersToFormula());
HSSFCell cell = wb.getSheet(cellRef.getSheetName()).getRow(cellRef.getRow()).getCell((int)cellRef.getCol());
assertEquals("VLOOKUP(PART,COSTS,2,FALSE)",cell.getCellFormula());
assertEquals("Sheet1!$D$2", wb.getName("COST").getRefersToFormula());
cellRef = new CellReference(wb.getName("COST").getRefersToFormula());
cell = wb.getSheet(cellRef.getSheetName()).getRow(cellRef.getRow()).getCell((int)cellRef.getCol());
assertEquals("UNITCOST*Quant",cell.getCellFormula());
assertEquals("Sheet1!$E$2", wb.getName("TOTALCOST").getRefersToFormula());
cellRef = new CellReference(wb.getName("TOTALCOST").getRefersToFormula());
cell = wb.getSheet(cellRef.getSheetName()).getRow(cellRef.getRow()).getCell((int)cellRef.getCol());
assertEquals("Cost*Markup_Cost",cell.getCellFormula());
}catch(Exception e){
fail();
}
}
public void testReadReferencedSheet() {
try{
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("XRefCalcData.xls");
assertEquals("CostSheet!$A$2:$B$3", wb.getName("COSTS").getRefersToFormula());
assertEquals("x123",wb.getSheet("CostSheet").getRow(1).getCell(0).getStringCellValue());
assertEquals(PART_COST,wb.getSheet("CostSheet").getRow(1).getCell(1).getNumericCellValue());
assertEquals("MarkupSheet!$B$1", wb.getName("Markup_Cost").getRefersToFormula());
assertEquals(MARKUP_COST_1,wb.getSheet("MarkupSheet").getRow(0).getCell(1).getNumericCellValue());
}catch(Exception e){
fail();
}
}
public void testEvaluate() throws Exception {
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("XRefCalc.xls");
HSSFWorkbook wb2 = HSSFTestDataSamples.openSampleWorkbook("XRefCalcData.xls");
CellReference cellRef = new CellReference(wb.getName("QUANT").getRefersToFormula());
HSSFCell cell = wb.getSheet(cellRef.getSheetName()).getRow(cellRef.getRow()).getCell((int)cellRef.getCol());
cell.setCellValue(NEW_QUANT);
cell = wb2.getSheet("CostSheet").getRow(1).getCell(1);
cell.setCellValue(NEW_PART_COST);
HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(wb);
HSSFFormulaEvaluator evaluatorCost = new HSSFFormulaEvaluator(wb2);
String[] bookNames = { "XRefCalc.xls", "XRefCalcData.xls" };
HSSFFormulaEvaluator[] evaluators = { evaluator, evaluatorCost, };
HSSFFormulaEvaluator.setupEnvironment(bookNames, evaluators);
cellRef = new CellReference(wb.getName("UNITCOST").getRefersToFormula());
HSSFCell uccell = wb.getSheet(cellRef.getSheetName()).getRow(cellRef.getRow()).getCell((int)cellRef.getCol());
cellRef = new CellReference(wb.getName("COST").getRefersToFormula());
HSSFCell ccell = wb.getSheet(cellRef.getSheetName()).getRow(cellRef.getRow()).getCell((int)cellRef.getCol());
cellRef = new CellReference(wb.getName("TOTALCOST").getRefersToFormula());
HSSFCell tccell = wb.getSheet(cellRef.getSheetName()).getRow(cellRef.getRow()).getCell((int)cellRef.getCol());
evaluator.evaluateFormulaCell(uccell);
evaluator.evaluateFormulaCell(ccell);
evaluator.evaluateFormulaCell(tccell);
assertEquals(NEW_PART_COST, uccell.getNumericCellValue());
assertEquals(NEW_PART_COST*NEW_QUANT, ccell.getNumericCellValue());
assertEquals(NEW_PART_COST*NEW_QUANT*MARKUP_COST_2, tccell.getNumericCellValue());
}
}

View File

@ -215,4 +215,65 @@ public final class TestHSSFFormulaEvaluator extends TestCase {
assertEquals(3, evalCount); assertEquals(3, evalCount);
assertEquals(2.0, ((NumberEval)ve).getNumberValue(), 0D); assertEquals(2.0, ((NumberEval)ve).getNumberValue(), 0D);
} }
/**
* Ensures that we can handle NameXPtgs in the formulas
* we parse.
*/
public void testXRefs() throws Exception {
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("XRefCalc.xls");
HSSFWorkbook wbData = HSSFTestDataSamples.openSampleWorkbook("XRefCalcData.xls");
Cell cell;
// VLookup on a name in another file
cell = wb.getSheetAt(0).getRow(1).getCell(2);
assertEquals(Cell.CELL_TYPE_FORMULA, cell.getCellType());
assertEquals(Cell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType());
assertEquals(12.30, cell.getNumericCellValue(), 0.0001);
// WARNING - this is wrong!
// The file name should be showing, but bug #45970 is fixed
// we seem to loose it
assertEquals("VLOOKUP(PART,COSTS,2,FALSE)", cell.getCellFormula());
// Simple reference to a name in another file
cell = wb.getSheetAt(0).getRow(1).getCell(4);
assertEquals(Cell.CELL_TYPE_FORMULA, cell.getCellType());
assertEquals(Cell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType());
assertEquals(36.90, cell.getNumericCellValue(), 0.0001);
// WARNING - this is wrong!
// The file name should be showing, but bug #45970 is fixed
// we seem to loose it
assertEquals("Cost*Markup_Cost", cell.getCellFormula());
// Evaluate the cells
HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(wb);
HSSFFormulaEvaluator.setupEnvironment(
new String[] { "XRefCalc.xls", "XRefCalcData.xls" },
new HSSFFormulaEvaluator[] {
eval,
new HSSFFormulaEvaluator(wbData)
}
);
eval.evaluateFormulaCell(
wb.getSheetAt(0).getRow(1).getCell(2)
);
eval.evaluateFormulaCell(
wb.getSheetAt(0).getRow(1).getCell(4)
);
// Re-check VLOOKUP one
cell = wb.getSheetAt(0).getRow(1).getCell(2);
assertEquals(Cell.CELL_TYPE_FORMULA, cell.getCellType());
assertEquals(Cell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType());
assertEquals(12.30, cell.getNumericCellValue(), 0.0001);
// Re-check ref one
cell = wb.getSheetAt(0).getRow(1).getCell(4);
assertEquals(Cell.CELL_TYPE_FORMULA, cell.getCellType());
assertEquals(Cell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType());
assertEquals(36.90, cell.getNumericCellValue(), 0.0001);
}
} }

Binary file not shown.

Binary file not shown.