Have WorkbookEvaluator process NameXPtgs, rather than returning a NameXEval which later places didn't handle. Largely allows us to process the .xls version of the test file for #56737 (but filenames aren't quite the same as in Excel)

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1611711 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2014-07-18 16:58:38 +00:00
parent d4a1239efa
commit 6e37f73018
5 changed files with 86 additions and 27 deletions

View File

@ -481,7 +481,8 @@ final class LinkTable {
}
// Does it exist via the external book block?
if (_externalBookBlocks.length > extBookIndex) {
ExternalBookBlock externalBook = _externalBookBlocks[extBookIndex];
if (externalBook._externalNameRecords.length > definedNameIndex) {
return _externalBookBlocks[extBookIndex].getNameText(definedNameIndex);
} else if (firstTabIndex == -2) {
// Workbook scoped name, not actually external after all

View File

@ -18,7 +18,6 @@
package org.apache.poi.ss.formula;
import org.apache.poi.ss.formula.eval.NameEval;
import org.apache.poi.ss.formula.eval.NameXEval;
import org.apache.poi.ss.formula.eval.NotImplementedFunctionException;
import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.functions.FreeRefFunction;
@ -48,8 +47,6 @@ final class UserDefinedFunction implements FreeRefFunction {
String functionName;
if (nameArg instanceof NameEval) {
functionName = ((NameEval) nameArg).getFunctionName();
} else if (nameArg instanceof NameXEval) {
functionName = ec.getWorkbook().resolveNameXText(((NameXEval) nameArg).getPtg());
} else {
throw new RuntimeException("First argument should be a NameEval, but got ("
+ nameArg.getClass().getName() + ")");

View File

@ -17,11 +17,32 @@
package org.apache.poi.ss.formula;
import java.util.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Stack;
import java.util.TreeSet;
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException;
import org.apache.poi.ss.formula.atp.AnalysisToolPak;
import org.apache.poi.ss.formula.eval.*;
import org.apache.poi.ss.formula.eval.BlankEval;
import org.apache.poi.ss.formula.eval.BoolEval;
import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.EvaluationException;
import org.apache.poi.ss.formula.eval.FunctionEval;
import org.apache.poi.ss.formula.eval.MissingArgEval;
import org.apache.poi.ss.formula.eval.NameEval;
import org.apache.poi.ss.formula.eval.NameXEval;
import org.apache.poi.ss.formula.eval.NotImplementedException;
import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.OperandResolver;
import org.apache.poi.ss.formula.eval.StringEval;
import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.functions.Choose;
import org.apache.poi.ss.formula.functions.FreeRefFunction;
import org.apache.poi.ss.formula.functions.Function;
import org.apache.poi.ss.formula.functions.IfFunc;
import org.apache.poi.ss.formula.ptg.Area3DPtg;
import org.apache.poi.ss.formula.ptg.AreaErrPtg;
import org.apache.poi.ss.formula.ptg.AreaPtg;
@ -49,14 +70,10 @@ import org.apache.poi.ss.formula.ptg.RefPtg;
import org.apache.poi.ss.formula.ptg.StringPtg;
import org.apache.poi.ss.formula.ptg.UnionPtg;
import org.apache.poi.ss.formula.ptg.UnknownPtg;
import org.apache.poi.ss.formula.functions.Choose;
import org.apache.poi.ss.formula.functions.FreeRefFunction;
import org.apache.poi.ss.formula.functions.IfFunc;
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
@ -613,20 +630,23 @@ public final class WorkbookEvaluator {
// consider converting all these (ptg instanceof XxxPtg) expressions to (ptg.getClass() == XxxPtg.class)
if (ptg instanceof NamePtg) {
// named ranges, macro functions
// Named ranges, macro functions
NamePtg namePtg = (NamePtg) ptg;
EvaluationName nameRecord = _workbook.getName(namePtg);
if (nameRecord.isFunctionName()) {
return new NameEval(nameRecord.getNameText());
}
if (nameRecord.hasFormula()) {
return evaluateNameFormula(nameRecord.getNameDefinition(), ec);
}
throw new RuntimeException("Don't now how to evalate name '" + nameRecord.getNameText() + "'");
return getEvalForNameRecord(nameRecord, ec);
}
if (ptg instanceof NameXPtg) {
return ec.getNameXEval(((NameXPtg) ptg));
// Externally defined named ranges or macro functions
NameXPtg nameXPtg = (NameXPtg)ptg;
ValueEval eval = ec.getNameXEval(nameXPtg);
if (eval instanceof NameXEval) {
// Could not be directly evaluated, so process as a name
return getEvalForNameX(nameXPtg, ec);
} else {
// Use the evaluated version
return eval;
}
}
if (ptg instanceof IntPtg) {
@ -682,6 +702,42 @@ public final class WorkbookEvaluator {
throw new RuntimeException("Unexpected ptg class (" + ptg.getClass().getName() + ")");
}
private ValueEval getEvalForNameRecord(EvaluationName nameRecord, OperationEvaluationContext ec) {
if (nameRecord.isFunctionName()) {
return new NameEval(nameRecord.getNameText());
}
if (nameRecord.hasFormula()) {
return evaluateNameFormula(nameRecord.getNameDefinition(), ec);
}
throw new RuntimeException("Don't now how to evalate name '" + nameRecord.getNameText() + "'");
}
private ValueEval getEvalForNameX(NameXPtg nameXPtg, OperationEvaluationContext ec) {
String name = _workbook.resolveNameXText(nameXPtg);
// Try to parse it as a name
int sheetNameAt = name.indexOf('!');
EvaluationName nameRecord = null;
if (sheetNameAt > -1) {
// Sheet based name
String sheetName = name.substring(0, sheetNameAt);
String nameName = name.substring(sheetNameAt+1);
nameRecord = _workbook.getName(nameName, _workbook.getSheetIndex(sheetName));
} else {
// Workbook based name
nameRecord = _workbook.getName(name, -1);
}
if (nameRecord != null) {
// Process it as a name
return getEvalForNameRecord(nameRecord, ec);
} else {
// Must be an external function
return new NameEval(name);
}
}
/**
* YK: Used by OperationEvaluationContext to resolve indirect names.
*/

View File

@ -2616,7 +2616,7 @@ public final class TestBugs extends BaseTestBugzillaIssues {
/**
* Formulas which reference named ranges, either in other
* sheets, or workbook scoped but in other workbooks.
* Currently failing with
* Used to fail with
* java.lang.RuntimeException: Unexpected eval class (org.apache.poi.ss.formula.eval.NameXEval)
*/
@Test
@ -2639,7 +2639,12 @@ public final class TestBugs extends BaseTestBugzillaIssues {
Cell cRefWName = s.getRow(2).getCell(3);
assertEquals("Defines!NR_To_A1", cRefSName.getCellFormula());
assertEquals("'56737.xls'!NR_Global_B2", cRefWName.getCellFormula());
// TODO How does Excel know to prefix this with the filename?
// This is what Excel itself shows
//assertEquals("'56737.xls'!NR_Global_B2", cRefWName.getCellFormula());
// TODO This isn't right, but it's what we currently generate....
assertEquals("NR_Global_B2", cRefWName.getCellFormula());
// Try to evaluate them
FormulaEvaluator eval = wb.getCreationHelper().createFormulaEvaluator();

View File

@ -19,18 +19,18 @@ package org.apache.poi.hssf.usermodel;
import junit.framework.AssertionFailedError;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.HSSFITestDataProvider;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.NameRecord;
import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.EvaluationCell;
import org.apache.poi.ss.formula.EvaluationListener;
import org.apache.poi.ss.formula.WorkbookEvaluator;
import org.apache.poi.ss.formula.WorkbookEvaluatorTestHelper;
import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.usermodel.BaseTestFormulaEvaluator;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellValue;
import org.apache.poi.ss.usermodel.BaseTestFormulaEvaluator;
/**
*