fixed formula parser to correctly resolve sheet-level names

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@729028 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yegor Kozlov 2008-12-23 16:19:07 +00:00
parent 98121b7691
commit 177533e23b
23 changed files with 343 additions and 206 deletions

View File

@ -37,6 +37,7 @@
<!-- Don't forget to update status.xml too! --> <!-- Don't forget to update status.xml too! -->
<release version="3.5-beta5" date="2008-??-??"> <release version="3.5-beta5" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="fix">fixed formula parser to correctly resolve sheet-level names</action>
<action dev="POI-DEVELOPERS" type="fix">46433 - support for shared formulas in XSSF</action> <action dev="POI-DEVELOPERS" type="fix">46433 - support for shared formulas in XSSF</action>
<action dev="POI-DEVELOPERS" type="add">46299 - support for carriage return and line break in XWPFRun</action> <action dev="POI-DEVELOPERS" type="add">46299 - support for carriage return and line break in XWPFRun</action>
<action dev="POI-DEVELOPERS" type="add">46300 - support for line spacing in XWPFParagraph</action> <action dev="POI-DEVELOPERS" type="add">46300 - support for line spacing in XWPFParagraph</action>

View File

@ -34,6 +34,7 @@
<!-- Don't forget to update changes.xml too! --> <!-- Don't forget to update changes.xml too! -->
<changes> <changes>
<release version="3.5-beta5" date="2008-??-??"> <release version="3.5-beta5" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="fix">fixed formula parser to correctly resolve sheet-level names</action>
<action dev="POI-DEVELOPERS" type="fix">46433 - support for shared formulas in XSSF</action> <action dev="POI-DEVELOPERS" type="fix">46433 - support for shared formulas in XSSF</action>
<action dev="POI-DEVELOPERS" type="add">46299 - support for carriage return and line break in XWPFRun</action> <action dev="POI-DEVELOPERS" type="add">46299 - support for carriage return and line break in XWPFRun</action>
<action dev="POI-DEVELOPERS" type="add">46300 - support for line spacing in XWPFParagraph</action> <action dev="POI-DEVELOPERS" type="add">46300 - support for line spacing in XWPFParagraph</action>

View File

@ -44,7 +44,7 @@ public final class HSSFFormulaParser {
* Convenience method for parsing cell formulas. see {@link #parse(String, HSSFWorkbook, int)} * Convenience method for parsing cell formulas. see {@link #parse(String, HSSFWorkbook, int)}
*/ */
public static Ptg[] parse(String formula, HSSFWorkbook workbook) { public static Ptg[] parse(String formula, HSSFWorkbook workbook) {
return FormulaParser.parse(formula, createParsingWorkbook(workbook)); return parse(formula, workbook, FormulaType.CELL);
} }
/** /**
@ -52,7 +52,21 @@ public final class HSSFFormulaParser {
* @return the parsed formula tokens * @return the parsed formula tokens
*/ */
public static Ptg[] parse(String formula, HSSFWorkbook workbook, int formulaType) { public static Ptg[] parse(String formula, HSSFWorkbook workbook, int formulaType) {
return FormulaParser.parse(formula, createParsingWorkbook(workbook), formulaType); return parse(formula, workbook, formulaType, -1);
}
/**
* @param formula the formula to parse
* @param workbook the parent workbook
* @param formulaType a constant from {@link FormulaType}
* @param sheetIndex the 0-based index of the sheet this formula belongs to.
* The sheet index is required to resolve sheet-level names. <code>-1</code> means that
* the scope of the name will be ignored and the parser will match named ranges only by name
*
* @return the parsed formula tokens
*/
public static Ptg[] parse(String formula, HSSFWorkbook workbook, int formulaType, int sheetIndex) {
return FormulaParser.parse(formula, createParsingWorkbook(workbook), formulaType, sheetIndex);
} }
/** /**

View File

@ -23,7 +23,9 @@ import org.apache.poi.hssf.record.cf.FontFormatting;
import org.apache.poi.hssf.record.cf.PatternFormatting; import org.apache.poi.hssf.record.cf.PatternFormatting;
import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.ss.formula.Formula; import org.apache.poi.ss.formula.Formula;
import org.apache.poi.ss.formula.FormulaType;
import org.apache.poi.util.BitField; import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
@ -132,18 +134,18 @@ public final class CFRuleRecord extends StandardRecord {
/** /**
* Creates a new comparison operation rule * Creates a new comparison operation rule
*/ */
public static CFRuleRecord create(HSSFWorkbook workbook, String formulaText) { public static CFRuleRecord create(HSSFSheet sheet, String formulaText) {
Ptg[] formula1 = parseFormula(formulaText, workbook); Ptg[] formula1 = parseFormula(formulaText, sheet);
return new CFRuleRecord(CONDITION_TYPE_FORMULA, ComparisonOperator.NO_COMPARISON, return new CFRuleRecord(CONDITION_TYPE_FORMULA, ComparisonOperator.NO_COMPARISON,
formula1, null); formula1, null);
} }
/** /**
* Creates a new comparison operation rule * Creates a new comparison operation rule
*/ */
public static CFRuleRecord create(HSSFWorkbook workbook, byte comparisonOperation, public static CFRuleRecord create(HSSFSheet sheet, byte comparisonOperation,
String formulaText1, String formulaText2) { String formulaText1, String formulaText2) {
Ptg[] formula1 = parseFormula(formulaText1, workbook); Ptg[] formula1 = parseFormula(formulaText1, sheet);
Ptg[] formula2 = parseFormula(formulaText2, workbook); Ptg[] formula2 = parseFormula(formulaText2, sheet);
return new CFRuleRecord(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation, formula1, formula2); return new CFRuleRecord(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation, formula1, formula2);
} }
@ -527,10 +529,11 @@ public final class CFRuleRecord extends StandardRecord {
* *
* @return <code>null</code> if <tt>formula</tt> was null. * @return <code>null</code> if <tt>formula</tt> was null.
*/ */
private static Ptg[] parseFormula(String formula, HSSFWorkbook workbook) { private static Ptg[] parseFormula(String formula, HSSFSheet sheet) {
if(formula == null) { if(formula == null) {
return null; return null;
} }
return HSSFFormulaParser.parse(formula, workbook); int sheetIndex = sheet.getWorkbook().getSheetIndex(sheet);
return HSSFFormulaParser.parse(formula, sheet.getWorkbook(), FormulaType.CELL, sheetIndex);
} }
} }

View File

@ -24,7 +24,6 @@ import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.formula.NumberPtg; import org.apache.poi.hssf.record.formula.NumberPtg;
import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.StringPtg; import org.apache.poi.hssf.record.formula.StringPtg;
import org.apache.poi.ss.formula.FormulaParser;
import org.apache.poi.ss.formula.FormulaType; import org.apache.poi.ss.formula.FormulaType;
/** /**
@ -324,24 +323,25 @@ public class DVConstraint {
/** /**
* @return both parsed formulas (for expression 1 and 2). * @return both parsed formulas (for expression 1 and 2).
*/ */
/* package */ FormulaPair createFormulas(HSSFWorkbook workbook) { /* package */ FormulaPair createFormulas(HSSFSheet sheet) {
Ptg[] formula1; Ptg[] formula1;
Ptg[] formula2; Ptg[] formula2;
if (isListValidationType()) { if (isListValidationType()) {
formula1 = createListFormula(workbook); formula1 = createListFormula(sheet);
formula2 = Ptg.EMPTY_PTG_ARRAY; formula2 = Ptg.EMPTY_PTG_ARRAY;
} else { } else {
formula1 = convertDoubleFormula(_formula1, _value1, workbook); formula1 = convertDoubleFormula(_formula1, _value1, sheet);
formula2 = convertDoubleFormula(_formula2, _value2, workbook); formula2 = convertDoubleFormula(_formula2, _value2, sheet);
} }
return new FormulaPair(formula1, formula2); return new FormulaPair(formula1, formula2);
} }
private Ptg[] createListFormula(HSSFWorkbook workbook) { private Ptg[] createListFormula(HSSFSheet sheet) {
if (_explicitListValues == null) { if (_explicitListValues == null) {
HSSFWorkbook wb = sheet.getWorkbook();
// formula is parsed with slightly different RVA rules: (root node type must be 'reference') // formula is parsed with slightly different RVA rules: (root node type must be 'reference')
return HSSFFormulaParser.parse(_formula1, workbook, FormulaType.DATAVALIDATION_LIST); return HSSFFormulaParser.parse(_formula1, wb, FormulaType.DATAVALIDATION_LIST, wb.getSheetIndex(sheet));
// To do: Excel places restrictions on the available operations within a list formula. // To do: Excel places restrictions on the available operations within a list formula.
// Some things like union and intersection are not allowed. // Some things like union and intersection are not allowed.
} }
@ -361,7 +361,7 @@ public class DVConstraint {
* @return The parsed token array representing the formula or value specified. * @return The parsed token array representing the formula or value specified.
* Empty array if both formula and value are <code>null</code> * Empty array if both formula and value are <code>null</code>
*/ */
private static Ptg[] convertDoubleFormula(String formula, Double value, HSSFWorkbook workbook) { private static Ptg[] convertDoubleFormula(String formula, Double value, HSSFSheet sheet) {
if (formula == null) { if (formula == null) {
if (value == null) { if (value == null) {
return Ptg.EMPTY_PTG_ARRAY; return Ptg.EMPTY_PTG_ARRAY;
@ -371,7 +371,8 @@ public class DVConstraint {
if (value != null) { if (value != null) {
throw new IllegalStateException("Both formula and value cannot be present"); throw new IllegalStateException("Both formula and value cannot be present");
} }
return HSSFFormulaParser.parse(formula, workbook); HSSFWorkbook wb = sheet.getWorkbook();
return HSSFFormulaParser.parse(formula, wb, FormulaType.CELL, wb.getSheetIndex(sheet));
} }

View File

@ -54,6 +54,7 @@ import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Comment; import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.Hyperlink; import org.apache.poi.ss.usermodel.Hyperlink;
import org.apache.poi.ss.usermodel.RichTextString; import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.formula.FormulaType;
/** /**
* High level representation of a cell in a row of a spreadsheet. * High level representation of a cell in a row of a spreadsheet.
@ -594,7 +595,8 @@ public class HSSFCell implements Cell {
setCellType(CELL_TYPE_BLANK, false, row, col, styleIndex); setCellType(CELL_TYPE_BLANK, false, row, col, styleIndex);
return; return;
} }
Ptg[] ptgs = HSSFFormulaParser.parse(formula, book); int sheetIndex = book.getSheetIndex(sheet);
Ptg[] ptgs = HSSFFormulaParser.parse(formula, book, FormulaType.CELL, sheetIndex);
setCellType(CELL_TYPE_FORMULA, false, row, col, styleIndex); setCellType(CELL_TYPE_FORMULA, false, row, col, styleIndex);
FormulaRecordAggregate agg = (FormulaRecordAggregate) record; FormulaRecordAggregate agg = (FormulaRecordAggregate) record;
FormulaRecord frec = agg.getFormulaRecord(); FormulaRecord frec = agg.getFormulaRecord();

View File

@ -219,9 +219,9 @@ public final class HSSFDataValidation {
return _error_text; return _error_text;
} }
public DVRecord createDVRecord(HSSFWorkbook workbook) { public DVRecord createDVRecord(HSSFSheet sheet) {
FormulaPair fp = _constraint.createFormulas(workbook); FormulaPair fp = _constraint.createFormulas(sheet);
return new DVRecord(_constraint.getValidationType(), return new DVRecord(_constraint.getValidationType(),
_constraint.getOperator(), _constraint.getOperator(),

View File

@ -24,12 +24,7 @@ import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
import org.apache.poi.hssf.record.formula.NamePtg; import org.apache.poi.hssf.record.formula.NamePtg;
import org.apache.poi.hssf.record.formula.NameXPtg; import org.apache.poi.hssf.record.formula.NameXPtg;
import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.ss.formula.EvaluationCell; import org.apache.poi.ss.formula.*;
import org.apache.poi.ss.formula.EvaluationName;
import org.apache.poi.ss.formula.EvaluationSheet;
import org.apache.poi.ss.formula.EvaluationWorkbook;
import org.apache.poi.ss.formula.FormulaParsingWorkbook;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
/** /**
* Internal POI use only * Internal POI use only
@ -65,14 +60,21 @@ public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
return _iBook.getNameXPtg(name); return _iBook.getNameXPtg(name);
} }
public EvaluationName getName(String name) { /**
* Lookup a named range by its name.
*
* @param name the name to search
* @param sheetIndex the 0-based index of the sheet this formula belongs to.
* The sheet index is required to resolve sheet-level names. <code>-1</code> means workbook-global names
*/
public EvaluationName getName(String name, int sheetIndex) {
for(int i=0; i < _iBook.getNumNames(); i++) { for(int i=0; i < _iBook.getNumNames(); i++) {
NameRecord nr = _iBook.getNameRecord(i); NameRecord nr = _iBook.getNameRecord(i);
if (name.equalsIgnoreCase(nr.getNameText())) { if (nr.getSheetNumber() == sheetIndex+1 && name.equalsIgnoreCase(nr.getNameText())) {
return new Name(nr, i); return new Name(nr, i);
} }
} }
return null; return sheetIndex == -1 ? null : getName(name, -1);
} }
public int getSheetIndex(EvaluationSheet evalSheet) { public int getSheetIndex(EvaluationSheet evalSheet) {
@ -118,7 +120,7 @@ public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
// re-parsing the formula text also works, but is a waste of time // re-parsing the formula text also works, but is a waste of time
// It is useful from time to time to run all unit tests with this code // It is useful from time to time to run all unit tests with this code
// to make sure that all formulas POI can evaluate can also be parsed. // to make sure that all formulas POI can evaluate can also be parsed.
return HSSFFormulaParser.parse(cell.getCellFormula(), _uBook); return HSSFFormulaParser.parse(cell.getCellFormula(), _uBook, FormulaType.CELL, _uBook.getSheetIndex(cell.getSheet()));
} }
FormulaRecordAggregate fra = (FormulaRecordAggregate) cell.getCellValueRecord(); FormulaRecordAggregate fra = (FormulaRecordAggregate) cell.getCellValueRecord();
return fra.getFormulaTokens(); return fra.getFormulaTokens();

View File

@ -163,7 +163,7 @@ public final class HSSFName implements Name {
* @throws IllegalArgumentException if the specified reference is unparsable * @throws IllegalArgumentException if the specified reference is unparsable
*/ */
public void setRefersToFormula(String formulaText) { public void setRefersToFormula(String formulaText) {
Ptg[] ptgs = HSSFFormulaParser.parse(formulaText, _book, FormulaType.NAMEDRANGE); Ptg[] ptgs = HSSFFormulaParser.parse(formulaText, _book, FormulaType.NAMEDRANGE, getSheetIndex());
_definedNameRec.setNameDefinition(ptgs); _definedNameRec.setNameDefinition(ptgs);
} }

View File

@ -367,7 +367,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
} }
DataValidityTable dvt = sheet.getOrCreateDataValidityTable(); DataValidityTable dvt = sheet.getOrCreateDataValidityTable();
DVRecord dvRecord = dataValidation.createDVRecord(workbook); DVRecord dvRecord = dataValidation.createDVRecord(this);
dvt.addDataValidation(dvRecord); dvt.addDataValidation(dvRecord);
} }
@ -1789,6 +1789,6 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
} }
public HSSFSheetConditionalFormatting getSheetConditionalFormatting() { public HSSFSheetConditionalFormatting getSheetConditionalFormatting() {
return new HSSFSheetConditionalFormatting(workbook, sheet); return new HSSFSheetConditionalFormatting(this);
} }
} }

View File

@ -31,12 +31,12 @@ import org.apache.poi.ss.util.CellRangeAddress;
*/ */
public final class HSSFSheetConditionalFormatting { public final class HSSFSheetConditionalFormatting {
private final HSSFWorkbook _workbook; private final HSSFSheet _sheet;
private final ConditionalFormattingTable _conditionalFormattingTable; private final ConditionalFormattingTable _conditionalFormattingTable;
/* package */ HSSFSheetConditionalFormatting(HSSFWorkbook workbook, Sheet sheet) { /* package */ HSSFSheetConditionalFormatting(HSSFSheet sheet) {
_workbook = workbook; _sheet = sheet;
_conditionalFormattingTable = sheet.getConditionalFormattingTable(); _conditionalFormattingTable = sheet.getSheet().getConditionalFormattingTable();
} }
/** /**
@ -67,8 +67,8 @@ public final class HSSFSheetConditionalFormatting {
String formula1, String formula1,
String formula2) { String formula2) {
HSSFWorkbook wb = _workbook; HSSFWorkbook wb = _sheet.getWorkbook();
CFRuleRecord rr = CFRuleRecord.create(wb, comparisonOperation, formula1, formula2); CFRuleRecord rr = CFRuleRecord.create(_sheet, comparisonOperation, formula1, formula2);
return new HSSFConditionalFormattingRule(wb, rr); return new HSSFConditionalFormattingRule(wb, rr);
} }
@ -80,8 +80,8 @@ public final class HSSFSheetConditionalFormatting {
* @param formula - formula for the valued, compared with the cell * @param formula - formula for the valued, compared with the cell
*/ */
public HSSFConditionalFormattingRule createConditionalFormattingRule(String formula) { public HSSFConditionalFormattingRule createConditionalFormattingRule(String formula) {
HSSFWorkbook wb = _workbook; HSSFWorkbook wb = _sheet.getWorkbook();
CFRuleRecord rr = CFRuleRecord.create(wb, formula); CFRuleRecord rr = CFRuleRecord.create(_sheet, formula);
return new HSSFConditionalFormattingRule(wb, rr); return new HSSFConditionalFormattingRule(wb, rr);
} }
@ -171,7 +171,7 @@ public final class HSSFSheetConditionalFormatting {
if (cf == null) { if (cf == null) {
return null; return null;
} }
return new HSSFConditionalFormatting(_workbook, cf); return new HSSFConditionalFormatting(_sheet.getWorkbook(), cf);
} }
/** /**

View File

@ -66,6 +66,7 @@ import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.CreationHelper; import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy; import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
import org.apache.poi.ss.formula.FormulaType;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
@ -1381,7 +1382,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
sb.append("!"); sb.append("!");
sb.append(parts[i]); sb.append(parts[i]);
} }
name.setNameDefinition(HSSFFormulaParser.parse(sb.toString(), this)); name.setNameDefinition(HSSFFormulaParser.parse(sb.toString(), this, FormulaType.CELL, sheetIndex));
} }
/** /**

View File

@ -142,6 +142,7 @@ public final class FormulaParser {
private FormulaParsingWorkbook _book; private FormulaParsingWorkbook _book;
private int _sheetIndex;
/** /**
@ -156,11 +157,12 @@ public final class FormulaParser {
* model.Workbook, then use the convenience method on * model.Workbook, then use the convenience method on
* usermodel.HSSFFormulaEvaluator * usermodel.HSSFFormulaEvaluator
*/ */
private FormulaParser(String formula, FormulaParsingWorkbook book){ private FormulaParser(String formula, FormulaParsingWorkbook book, int sheetIndex){
_formulaString = formula; _formulaString = formula;
_pointer=0; _pointer=0;
_book = book; _book = book;
_formulaLength = _formulaString.length(); _formulaLength = _formulaString.length();
_sheetIndex = sheetIndex;
} }
public static Ptg[] parse(String formula, FormulaParsingWorkbook book) { public static Ptg[] parse(String formula, FormulaParsingWorkbook book) {
@ -168,7 +170,24 @@ public final class FormulaParser {
} }
public static Ptg[] parse(String formula, FormulaParsingWorkbook workbook, int formulaType) { public static Ptg[] parse(String formula, FormulaParsingWorkbook workbook, int formulaType) {
FormulaParser fp = new FormulaParser(formula, workbook); return parse(formula, workbook, formulaType, -1);
}
/**
* Parse a formula into a array of tokens
*
* @param formula the formula to parse
* @param workbook the parent workbook
* @param formulaType the type of the formula, see {@link FormulaType}
* @param sheetIndex the 0-based index of the sheet this formula belongs to.
* The sheet index is required to resolve sheet-level names. <code>-1</code> means that
* the scope of the name will be ignored and the parser will match names only by name
*
* @return array of parsed tokens
* @throws FormulaParseException if the formula is unparsable
*/
public static Ptg[] parse(String formula, FormulaParsingWorkbook workbook, int formulaType, int sheetIndex) {
FormulaParser fp = new FormulaParser(formula, workbook, sheetIndex);
fp.parse(); fp.parse();
return fp.getRPNPtg(formulaType); return fp.getRPNPtg(formulaType);
} }
@ -413,7 +432,7 @@ public final class FormulaParser {
new FormulaParseException("Name '" + name new FormulaParseException("Name '" + name
+ "' does not look like a cell reference or named range"); + "' does not look like a cell reference or named range");
} }
EvaluationName evalName = _book.getName(name); EvaluationName evalName = _book.getName(name, _sheetIndex);
if (evalName == null) { if (evalName == null) {
throw new FormulaParseException("Specified named range '" throw new FormulaParseException("Specified named range '"
+ name + "' does not exist in the current workbook."); + name + "' does not exist in the current workbook.");
@ -516,7 +535,7 @@ public final class FormulaParser {
// user defined function // user defined function
// in the token tree, the name is more or less the first argument // in the token tree, the name is more or less the first argument
EvaluationName hName = _book.getName(name); EvaluationName hName = _book.getName(name, _sheetIndex);
if (hName == null) { if (hName == null) {
nameToken = _book.getNameXPtg(name); nameToken = _book.getNameXPtg(name);

View File

@ -30,7 +30,7 @@ public interface FormulaParsingWorkbook {
/** /**
* named range name matching is case insensitive * named range name matching is case insensitive
*/ */
EvaluationName getName(String name); EvaluationName getName(String name, int sheetIndex);
NameXPtg getNameXPtg(String name); NameXPtg getNameXPtg(String name);

View File

@ -347,8 +347,9 @@ public final class XSSFCell implements Cell {
throw new IllegalStateException("Shared Formula not found for group index " + idx); throw new IllegalStateException("Shared Formula not found for group index " + idx);
} }
String sharedFormula = sfCell.getCTCell().getF().getStringValue(); String sharedFormula = sfCell.getCTCell().getF().getStringValue();
int sheetIndex = sheet.getWorkbook().getSheetIndex(sheet);
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(sheet.getWorkbook()); XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(sheet.getWorkbook());
Ptg[] ptgs = FormulaParser.parse(sharedFormula, fpb); Ptg[] ptgs = FormulaParser.parse(sharedFormula, fpb, FormulaType.CELL, sheetIndex);
Ptg[] fmla = SharedFormulaRecord.convertSharedFormulas(ptgs, Ptg[] fmla = SharedFormulaRecord.convertSharedFormulas(ptgs,
getRowIndex() - sfCell.getRowIndex(), getColumnIndex() - sfCell.getColumnIndex()); getRowIndex() - sfCell.getRowIndex(), getColumnIndex() - sfCell.getColumnIndex());
return FormulaRenderer.toFormulaString(fpb, fmla); return FormulaRenderer.toFormulaString(fpb, fmla);
@ -371,9 +372,10 @@ public final class XSSFCell implements Cell {
return; return;
} }
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(row.getSheet().getWorkbook()); XSSFWorkbook wb = row.getSheet().getWorkbook();
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
try { try {
Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.CELL); Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.CELL, wb.getSheetIndex(getSheet()));
} catch (RuntimeException e) { } catch (RuntimeException e) {
if (e.getClass().getName().startsWith(FormulaParser.class.getName())) { if (e.getClass().getName().startsWith(FormulaParser.class.getName())) {
throw new IllegalArgumentException("Unparsable formula '" + formula + "'", e); throw new IllegalArgumentException("Unparsable formula '" + formula + "'", e);

View File

@ -20,13 +20,7 @@ package org.apache.poi.xssf.usermodel;
import org.apache.poi.hssf.record.formula.NamePtg; import org.apache.poi.hssf.record.formula.NamePtg;
import org.apache.poi.hssf.record.formula.NameXPtg; import org.apache.poi.hssf.record.formula.NameXPtg;
import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.ss.formula.EvaluationCell; import org.apache.poi.ss.formula.*;
import org.apache.poi.ss.formula.EvaluationName;
import org.apache.poi.ss.formula.EvaluationSheet;
import org.apache.poi.ss.formula.EvaluationWorkbook;
import org.apache.poi.ss.formula.FormulaParser;
import org.apache.poi.ss.formula.FormulaParsingWorkbook;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;
/** /**
@ -73,14 +67,15 @@ public final class XSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
return convertToExternalSheetIndex(sheetIndex); return convertToExternalSheetIndex(sheetIndex);
} }
public EvaluationName getName(String name) { public EvaluationName getName(String name, int sheetIndex) {
for(int i=0; i < _uBook.getNumberOfNames(); i++) { for(int i=0; i < _uBook.getNumberOfNames(); i++) {
String nameText = _uBook.getNameAt(i).getNameName(); XSSFName nm = _uBook.getNameAt(i);
if (name.equalsIgnoreCase(nameText)) { String nameText = nm.getNameName();
if (name.equalsIgnoreCase(nameText) && nm.getSheetIndex() == sheetIndex) {
return new Name(_uBook.getNameAt(i), i, this); return new Name(_uBook.getNameAt(i), i, this);
} }
} }
return null; return sheetIndex == -1 ? null : getName(name, -1);
} }
public int getSheetIndex(EvaluationSheet evalSheet) { public int getSheetIndex(EvaluationSheet evalSheet) {
@ -135,7 +130,7 @@ public final class XSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
public Ptg[] getFormulaTokens(EvaluationCell evalCell) { public Ptg[] getFormulaTokens(EvaluationCell evalCell) {
XSSFCell cell = ((XSSFEvaluationCell)evalCell).getXSSFCell(); XSSFCell cell = ((XSSFEvaluationCell)evalCell).getXSSFCell();
XSSFEvaluationWorkbook frBook = XSSFEvaluationWorkbook.create(_uBook); XSSFEvaluationWorkbook frBook = XSSFEvaluationWorkbook.create(_uBook);
return FormulaParser.parse(cell.getCellFormula(), frBook); return FormulaParser.parse(cell.getCellFormula(), frBook, FormulaType.CELL, _uBook.getSheetIndex(cell.getSheet()));
} }
private static final class Name implements EvaluationName { private static final class Name implements EvaluationName {
@ -152,7 +147,7 @@ public final class XSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
public Ptg[] getNameDefinition() { public Ptg[] getNameDefinition() {
return FormulaParser.parse(_nameRecord.getRefersToFormula(), _fpBook); return FormulaParser.parse(_nameRecord.getRefersToFormula(), _fpBook, FormulaType.NAMEDRANGE, _nameRecord.getSheetIndex());
} }
public String getNameText() { public String getNameText() {

View File

@ -199,7 +199,7 @@ public final class XSSFName implements Name {
public void setRefersToFormula(String formulaText) { public void setRefersToFormula(String formulaText) {
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(workbook); XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(workbook);
try { try {
Ptg[] ptgs = FormulaParser.parse(formulaText, fpb, FormulaType.NAMEDRANGE); Ptg[] ptgs = FormulaParser.parse(formulaText, fpb, FormulaType.NAMEDRANGE, getSheetIndex());
} catch (RuntimeException e) { } catch (RuntimeException e) {
if (e.getClass().getName().startsWith(FormulaParser.class.getName())) { if (e.getClass().getName().startsWith(FormulaParser.class.getName())) {
throw new IllegalArgumentException("Unparsable formula '" + formulaText + "'", e); throw new IllegalArgumentException("Unparsable formula '" + formulaText + "'", e);

View File

@ -121,4 +121,41 @@ public final class TestXSSFFormulaEvaluation extends TestCase {
assertEquals("B5", cell.getCellFormula()); assertEquals("B5", cell.getCellFormula());
assertEquals("UniqueDocumentNumberID", evaluator.evaluate(cell).getStringValue()); assertEquals("UniqueDocumentNumberID", evaluator.evaluate(cell).getStringValue());
} }
/**
* Test creation / evaluation of formulas with sheet-level names
*/
public void testSheetLevelFormulas(){
XSSFWorkbook wb = new XSSFWorkbook();
XSSFRow row;
XSSFSheet sh1 = wb.createSheet("Sheet1");
XSSFName nm1 = wb.createName();
nm1.setNameName("sales_1");
nm1.setSheetIndex(0);
nm1.setRefersToFormula("Sheet1!$A$1");
row = sh1.createRow(0);
row.createCell(0).setCellValue(3);
row.createCell(1).setCellFormula("sales_1");
row.createCell(2).setCellFormula("sales_1*2");
XSSFSheet sh2 = wb.createSheet("Sheet2");
XSSFName nm2 = wb.createName();
nm2.setNameName("sales_1");
nm2.setSheetIndex(1);
nm2.setRefersToFormula("Sheet2!$A$1");
row = sh2.createRow(0);
row.createCell(0).setCellValue(5);
row.createCell(1).setCellFormula("sales_1");
row.createCell(2).setCellFormula("sales_1*3");
XSSFFormulaEvaluator evaluator = new XSSFFormulaEvaluator(wb);
assertEquals(3.0, evaluator.evaluate(sh1.getRow(0).getCell(1)).getNumberValue());
assertEquals(6.0, evaluator.evaluate(sh1.getRow(0).getCell(2)).getNumberValue());
assertEquals(5.0, evaluator.evaluate(sh2.getRow(0).getCell(1)).getNumberValue());
assertEquals(15.0, evaluator.evaluate(sh2.getRow(0).getCell(2)).getNumberValue());
}
} }

View File

@ -28,6 +28,7 @@ import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.RefNPtg; import org.apache.poi.hssf.record.formula.RefNPtg;
import org.apache.poi.hssf.record.formula.RefPtg; import org.apache.poi.hssf.record.formula.RefPtg;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.ss.formula.Formula; import org.apache.poi.ss.formula.Formula;
@ -43,20 +44,21 @@ public final class TestCFRuleRecord extends TestCase
public void testConstructors () public void testConstructors ()
{ {
HSSFWorkbook workbook = new HSSFWorkbook(); HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet();
CFRuleRecord rule1 = CFRuleRecord.create(workbook, "7"); CFRuleRecord rule1 = CFRuleRecord.create(sheet, "7");
assertEquals(CFRuleRecord.CONDITION_TYPE_FORMULA, rule1.getConditionType()); assertEquals(CFRuleRecord.CONDITION_TYPE_FORMULA, rule1.getConditionType());
assertEquals(ComparisonOperator.NO_COMPARISON, rule1.getComparisonOperation()); assertEquals(ComparisonOperator.NO_COMPARISON, rule1.getComparisonOperation());
assertNotNull(rule1.getParsedExpression1()); assertNotNull(rule1.getParsedExpression1());
assertSame(Ptg.EMPTY_PTG_ARRAY, rule1.getParsedExpression2()); assertSame(Ptg.EMPTY_PTG_ARRAY, rule1.getParsedExpression2());
CFRuleRecord rule2 = CFRuleRecord.create(workbook, ComparisonOperator.BETWEEN, "2", "5"); CFRuleRecord rule2 = CFRuleRecord.create(sheet, ComparisonOperator.BETWEEN, "2", "5");
assertEquals(CFRuleRecord.CONDITION_TYPE_CELL_VALUE_IS, rule2.getConditionType()); assertEquals(CFRuleRecord.CONDITION_TYPE_CELL_VALUE_IS, rule2.getConditionType());
assertEquals(ComparisonOperator.BETWEEN, rule2.getComparisonOperation()); assertEquals(ComparisonOperator.BETWEEN, rule2.getComparisonOperation());
assertNotNull(rule2.getParsedExpression1()); assertNotNull(rule2.getParsedExpression1());
assertNotNull(rule2.getParsedExpression2()); assertNotNull(rule2.getParsedExpression2());
CFRuleRecord rule3 = CFRuleRecord.create(workbook, ComparisonOperator.EQUAL, null, null); CFRuleRecord rule3 = CFRuleRecord.create(sheet, ComparisonOperator.EQUAL, null, null);
assertEquals(CFRuleRecord.CONDITION_TYPE_CELL_VALUE_IS, rule3.getConditionType()); assertEquals(CFRuleRecord.CONDITION_TYPE_CELL_VALUE_IS, rule3.getConditionType());
assertEquals(ComparisonOperator.EQUAL, rule3.getComparisonOperation()); assertEquals(ComparisonOperator.EQUAL, rule3.getComparisonOperation());
assertSame(Ptg.EMPTY_PTG_ARRAY, rule3.getParsedExpression2()); assertSame(Ptg.EMPTY_PTG_ARRAY, rule3.getParsedExpression2());
@ -66,7 +68,8 @@ public final class TestCFRuleRecord extends TestCase
public void testCreateCFRuleRecord () public void testCreateCFRuleRecord ()
{ {
HSSFWorkbook workbook = new HSSFWorkbook(); HSSFWorkbook workbook = new HSSFWorkbook();
CFRuleRecord record = CFRuleRecord.create(workbook, "7"); HSSFSheet sheet = workbook.createSheet();
CFRuleRecord record = CFRuleRecord.create(sheet, "7");
testCFRuleRecord(record); testCFRuleRecord(record);
// Serialize // Serialize
@ -306,7 +309,8 @@ public final class TestCFRuleRecord extends TestCase
public void testWrite() { public void testWrite() {
HSSFWorkbook workbook = new HSSFWorkbook(); HSSFWorkbook workbook = new HSSFWorkbook();
CFRuleRecord rr = CFRuleRecord.create(workbook, ComparisonOperator.BETWEEN, "5", "10"); HSSFSheet sheet = workbook.createSheet();
CFRuleRecord rr = CFRuleRecord.create(sheet, ComparisonOperator.BETWEEN, "5", "10");
PatternFormatting patternFormatting = new PatternFormatting(); PatternFormatting patternFormatting = new PatternFormatting();
patternFormatting.setFillPattern(PatternFormatting.BRICKS); patternFormatting.setFillPattern(PatternFormatting.BRICKS);

View File

@ -31,6 +31,7 @@ import org.apache.poi.hssf.record.CFRuleRecord;
import org.apache.poi.hssf.record.RecordFactory; import org.apache.poi.hssf.record.RecordFactory;
import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator; import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
@ -46,11 +47,13 @@ public final class TestCFRecordsAggregate extends TestCase
public void testCFRecordsAggregate() public void testCFRecordsAggregate()
{ {
HSSFWorkbook workbook = new HSSFWorkbook(); HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet();
List recs = new ArrayList(); List recs = new ArrayList();
CFHeaderRecord header = new CFHeaderRecord(); CFHeaderRecord header = new CFHeaderRecord();
CFRuleRecord rule1 = CFRuleRecord.create(workbook, "7"); CFRuleRecord rule1 = CFRuleRecord.create(sheet, "7");
CFRuleRecord rule2 = CFRuleRecord.create(workbook, ComparisonOperator.BETWEEN, "2", "5"); CFRuleRecord rule2 = CFRuleRecord.create(sheet, ComparisonOperator.BETWEEN, "2", "5");
CFRuleRecord rule3 = CFRuleRecord.create(workbook, ComparisonOperator.GE, "100", null); CFRuleRecord rule3 = CFRuleRecord.create(sheet, ComparisonOperator.GE, "100", null);
header.setNumberOfConditionalFormats(3); header.setNumberOfConditionalFormats(3);
CellRangeAddress[] cellRanges = { CellRangeAddress[] cellRanges = {
new CellRangeAddress(0,1,0,0), new CellRangeAddress(0,1,0,0),
@ -107,13 +110,14 @@ public final class TestCFRecordsAggregate extends TestCase
*/ */
public void testNRules() { public void testNRules() {
HSSFWorkbook workbook = new HSSFWorkbook(); HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet();
CellRangeAddress[] cellRanges = { CellRangeAddress[] cellRanges = {
new CellRangeAddress(0,1,0,0), new CellRangeAddress(0,1,0,0),
new CellRangeAddress(0,1,2,2), new CellRangeAddress(0,1,2,2),
}; };
CFRuleRecord[] rules = { CFRuleRecord[] rules = {
CFRuleRecord.create(workbook, "7"), CFRuleRecord.create(sheet, "7"),
CFRuleRecord.create(workbook, ComparisonOperator.BETWEEN, "2", "5"), CFRuleRecord.create(sheet, ComparisonOperator.BETWEEN, "2", "5"),
}; };
CFRecordsAggregate agg = new CFRecordsAggregate(cellRanges, rules); CFRecordsAggregate agg = new CFRecordsAggregate(cellRanges, rules);
byte[] serializedRecord = new byte[agg.getRecordSize()]; byte[] serializedRecord = new byte[agg.getRecordSize()];

View File

@ -25,8 +25,12 @@ import java.util.Date;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.NamePtg;
import org.apache.poi.hssf.util.CellReference; import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.util.TempFile; import org.apache.poi.util.TempFile;
import org.apache.poi.ss.formula.FormulaType;
/** /**
* @author Andrew C. Oliver (acoliver at apache dot org) * @author Andrew C. Oliver (acoliver at apache dot org)
@ -884,4 +888,51 @@ public final class TestFormulas extends TestCase {
assertEquals("DZ2*2", wb.getSheetAt(0).getRow(1).getCell(128).toString()); assertEquals("DZ2*2", wb.getSheetAt(0).getRow(1).getCell(128).toString());
assertEquals("B32770*2", wb.getSheetAt(0).getRow(32768).getCell(1).toString()); assertEquals("B32770*2", wb.getSheetAt(0).getRow(32768).getCell(1).toString());
} }
/**
* Test creation / evaluation of formulas with sheet-level names
*/
public void testSheetLevelFormulas(){
HSSFWorkbook wb = new HSSFWorkbook();
HSSFRow row;
HSSFSheet sh1 = wb.createSheet("Sheet1");
HSSFName nm1 = wb.createName();
nm1.setNameName("sales_1");
nm1.setSheetIndex(0);
nm1.setRefersToFormula("Sheet1!$A$1");
row = sh1.createRow(0);
row.createCell(0).setCellValue(3);
row.createCell(1).setCellFormula("sales_1");
row.createCell(2).setCellFormula("sales_1*2");
HSSFSheet sh2 = wb.createSheet("Sheet2");
HSSFName nm2 = wb.createName();
nm2.setNameName("sales_1");
nm2.setSheetIndex(1);
nm2.setRefersToFormula("Sheet2!$A$1");
row = sh2.createRow(0);
row.createCell(0).setCellValue(5);
row.createCell(1).setCellFormula("sales_1");
row.createCell(2).setCellFormula("sales_1*3");
//check that NamePtg refers to the correct NameRecord
Ptg[] ptgs1 = HSSFFormulaParser.parse("sales_1", wb, FormulaType.CELL, 0);
NamePtg nPtg1 = (NamePtg)ptgs1[0];
assertSame(nm1, wb.getNameAt(nPtg1.getIndex()));
Ptg[] ptgs2 = HSSFFormulaParser.parse("sales_1", wb, FormulaType.CELL, 1);
NamePtg nPtg2 = (NamePtg)ptgs2[0];
assertSame(nm2, wb.getNameAt(nPtg2.getIndex()));
//check that the formula evaluator returns the correct result
HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(wb);
assertEquals(3.0, evaluator.evaluate(sh1.getRow(0).getCell(1)).getNumberValue());
assertEquals(6.0, evaluator.evaluate(sh1.getRow(0).getCell(2)).getNumberValue());
assertEquals(5.0, evaluator.evaluate(sh2.getRow(0).getCell(1)).getNumberValue());
assertEquals(15.0, evaluator.evaluate(sh2.getRow(0).getCell(2)).getNumberValue());
}
} }

View File

@ -543,7 +543,7 @@ public final class TestNamedRange extends TestCase {
HSSFWorkbook wb = new HSSFWorkbook(); HSSFWorkbook wb = new HSSFWorkbook();
wb.createSheet("CSCO"); wb.createSheet("CSCO");
Ptg[] ptgs = HSSFFormulaParser.parse("CSCO!$E$71", wb, FormulaType.NAMEDRANGE); Ptg[] ptgs = HSSFFormulaParser.parse("CSCO!$E$71", wb, FormulaType.NAMEDRANGE, 0);
for (int i = 0; i < ptgs.length; i++) { for (int i = 0; i < ptgs.length; i++) {
assertEquals('R', ptgs[i].getRVAType()); assertEquals('R', ptgs[i].getRVAType());
} }