<!-- Don't forget to update status.xml too! -->
<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="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>
<!-- Don't forget to update changes.xml too! -->
<changes>
<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="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>
* Convenience method for parsing cell formulas. see {@link #parse(String, HSSFWorkbook, int)}\r
*/\r
public static Ptg[] parse(String formula, HSSFWorkbook workbook) {\r
- return FormulaParser.parse(formula, createParsingWorkbook(workbook));\r
+ return parse(formula, workbook, FormulaType.CELL);\r
}\r
\r
/**\r
* @return the parsed formula tokens\r
*/\r
public static Ptg[] parse(String formula, HSSFWorkbook workbook, int formulaType) {\r
- return FormulaParser.parse(formula, createParsingWorkbook(workbook), formulaType);\r
+ return parse(formula, workbook, formulaType, -1);\r
}\r
\r
+ /**\r
+ * @param formula the formula to parse\r
+ * @param workbook the parent workbook\r
+ * @param formulaType a constant from {@link FormulaType}\r
+ * @param sheetIndex the 0-based index of the sheet this formula belongs to.\r
+ * The sheet index is required to resolve sheet-level names. <code>-1</code> means that\r
+ * the scope of the name will be ignored and the parser will match named ranges only by name\r
+ *\r
+ * @return the parsed formula tokens\r
+ */\r
+ public static Ptg[] parse(String formula, HSSFWorkbook workbook, int formulaType, int sheetIndex) {\r
+ return FormulaParser.parse(formula, createParsingWorkbook(workbook), formulaType, sheetIndex);\r
+ }\r
+\r
/**\r
* Static method to convert an array of {@link Ptg}s in RPN order\r
* to a human readable string format in infix mode.\r
import org.apache.poi.hssf.record.cf.PatternFormatting;
import org.apache.poi.hssf.record.formula.Ptg;
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.FormulaType;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndianOutput;
/**
* Creates a new comparison operation rule
*/
- public static CFRuleRecord create(HSSFWorkbook workbook, String formulaText) {
- Ptg[] formula1 = parseFormula(formulaText, workbook);
- return new CFRuleRecord(CONDITION_TYPE_FORMULA, ComparisonOperator.NO_COMPARISON,
- formula1, null);
- }
+ public static CFRuleRecord create(HSSFSheet sheet, String formulaText) {
+ Ptg[] formula1 = parseFormula(formulaText, sheet);
+ return new CFRuleRecord(CONDITION_TYPE_FORMULA, ComparisonOperator.NO_COMPARISON,
+ formula1, null);
+ }
/**
* 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) {
- Ptg[] formula1 = parseFormula(formulaText1, workbook);
- Ptg[] formula2 = parseFormula(formulaText2, workbook);
+ Ptg[] formula1 = parseFormula(formulaText1, sheet);
+ Ptg[] formula2 = parseFormula(formulaText2, sheet);
return new CFRuleRecord(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation, formula1, formula2);
}
*
* @return <code>null</code> if <tt>formula</tt> was null.
*/
- private static Ptg[] parseFormula(String formula, HSSFWorkbook workbook) {
- if(formula == null) {
- return null;
- }
- return HSSFFormulaParser.parse(formula, workbook);
- }
+ private static Ptg[] parseFormula(String formula, HSSFSheet sheet) {
+ if(formula == null) {
+ return null;
+ }
+ int sheetIndex = sheet.getWorkbook().getSheetIndex(sheet);
+ return HSSFFormulaParser.parse(formula, sheet.getWorkbook(), FormulaType.CELL, sheetIndex);
+ }
}
import org.apache.poi.hssf.record.formula.NumberPtg;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.StringPtg;
-import org.apache.poi.ss.formula.FormulaParser;
import org.apache.poi.ss.formula.FormulaType;
/**
/**
* @return both parsed formulas (for expression 1 and 2).
*/
- /* package */ FormulaPair createFormulas(HSSFWorkbook workbook) {
+ /* package */ FormulaPair createFormulas(HSSFSheet sheet) {
Ptg[] formula1;
Ptg[] formula2;
if (isListValidationType()) {
- formula1 = createListFormula(workbook);
+ formula1 = createListFormula(sheet);
formula2 = Ptg.EMPTY_PTG_ARRAY;
} else {
- formula1 = convertDoubleFormula(_formula1, _value1, workbook);
- formula2 = convertDoubleFormula(_formula2, _value2, workbook);
+ formula1 = convertDoubleFormula(_formula1, _value1, sheet);
+ formula2 = convertDoubleFormula(_formula2, _value2, sheet);
}
return new FormulaPair(formula1, formula2);
}
- private Ptg[] createListFormula(HSSFWorkbook workbook) {
+ private Ptg[] createListFormula(HSSFSheet sheet) {
if (_explicitListValues == null) {
- // formula is parsed with slightly different RVA rules: (root node type must be 'reference')
- return HSSFFormulaParser.parse(_formula1, workbook, FormulaType.DATAVALIDATION_LIST);
+ HSSFWorkbook wb = sheet.getWorkbook();
+ // formula is parsed with slightly different RVA rules: (root node type must be 'reference')
+ return HSSFFormulaParser.parse(_formula1, wb, FormulaType.DATAVALIDATION_LIST, wb.getSheetIndex(sheet));
// To do: Excel places restrictions on the available operations within a list formula.
// Some things like union and intersection are not allowed.
}
* @return The parsed token array representing the formula or value specified.
* 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 (value == null) {
return Ptg.EMPTY_PTG_ARRAY;
if (value != null) {
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));
}
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.Hyperlink;
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.
public short getCellNum() {
return (short) getColumnIndex();
}
-
+
public int getColumnIndex() {
return record.getColumn() & 0xFFFF;
}
setCellType(CELL_TYPE_BLANK, false, row, col, styleIndex);
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);
FormulaRecordAggregate agg = (FormulaRecordAggregate) record;
FormulaRecord frec = agg.getFormulaRecord();
* @see org.apache.poi.hssf.usermodel.HSSFWorkbook#getCellStyleAt(short)
*/
public void setCellStyle(CellStyle style) {
- setCellStyle( (HSSFCellStyle)style );
+ setCellStyle( (HSSFCellStyle)style );
}
public void setCellStyle(HSSFCellStyle style) {
// Verify it really does belong to our workbook
* @param hyperlink hypelrink associated with this cell
*/
public void setHyperlink(Hyperlink hyperlink){
- HSSFHyperlink link = (HSSFHyperlink)hyperlink;
-
+ HSSFHyperlink link = (HSSFHyperlink)hyperlink;
+
link.setFirstRow(record.getRow());
link.setLastRow(record.getRow());
link.setFirstColumn(record.getColumn());
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(),
_constraint.getOperator(),
import org.apache.poi.hssf.record.formula.NamePtg;\r
import org.apache.poi.hssf.record.formula.NameXPtg;\r
import org.apache.poi.hssf.record.formula.Ptg;\r
-import org.apache.poi.ss.formula.EvaluationCell;\r
-import org.apache.poi.ss.formula.EvaluationName;\r
-import org.apache.poi.ss.formula.EvaluationSheet;\r
-import org.apache.poi.ss.formula.EvaluationWorkbook;\r
-import org.apache.poi.ss.formula.FormulaParsingWorkbook;\r
-import org.apache.poi.ss.formula.FormulaRenderingWorkbook;\r
+import org.apache.poi.ss.formula.*;\r
\r
/**\r
* Internal POI use only\r
*/\r
public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, EvaluationWorkbook, FormulaParsingWorkbook {\r
\r
- private final HSSFWorkbook _uBook;\r
- private final Workbook _iBook;\r
- \r
- public static HSSFEvaluationWorkbook create(HSSFWorkbook book) {\r
- if (book == null) {\r
- return null;\r
- }\r
- return new HSSFEvaluationWorkbook(book);\r
- }\r
-\r
- private HSSFEvaluationWorkbook(HSSFWorkbook book) {\r
- _uBook = book;\r
- _iBook = book.getWorkbook();\r
- }\r
-\r
- public int getExternalSheetIndex(String sheetName) {\r
- int sheetIndex = _uBook.getSheetIndex(sheetName);\r
- return _iBook.checkExternSheet(sheetIndex);\r
- }\r
- public int getExternalSheetIndex(String workbookName, String sheetName) {\r
- return _iBook.getExternalSheetIndex(workbookName, sheetName);\r
- }\r
-\r
- public NameXPtg getNameXPtg(String name) {\r
- return _iBook.getNameXPtg(name);\r
- }\r
-\r
- public EvaluationName getName(String name) {\r
- for(int i=0; i < _iBook.getNumNames(); i++) {\r
- NameRecord nr = _iBook.getNameRecord(i);\r
- if (name.equalsIgnoreCase(nr.getNameText())) {\r
- return new Name(nr, i);\r
- }\r
- }\r
- return null;\r
- }\r
-\r
- public int getSheetIndex(EvaluationSheet evalSheet) {\r
- HSSFSheet sheet = ((HSSFEvaluationSheet)evalSheet).getHSSFSheet();\r
- return _uBook.getSheetIndex(sheet);\r
- }\r
- public int getSheetIndex(String sheetName) {\r
- return _uBook.getSheetIndex(sheetName);\r
- }\r
-\r
- public String getSheetName(int sheetIndex) {\r
- return _uBook.getSheetName(sheetIndex);\r
- }\r
-\r
- public EvaluationSheet getSheet(int sheetIndex) {\r
- return new HSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex));\r
- }\r
- public int convertFromExternSheetIndex(int externSheetIndex) {\r
- return _iBook.getSheetIndexFromExternSheetIndex(externSheetIndex);\r
- }\r
-\r
- public ExternalSheet getExternalSheet(int externSheetIndex) {\r
- return _iBook.getExternalSheet(externSheetIndex);\r
- }\r
-\r
- public String resolveNameXText(NameXPtg n) {\r
- return _iBook.resolveNameXText(n.getSheetRefIndex(), n.getNameIndex());\r
- }\r
-\r
- public String getSheetNameByExternSheet(int externSheetIndex) {\r
- return _iBook.findSheetNameFromExternSheet(externSheetIndex);\r
- }\r
- public String getNameText(NamePtg namePtg) {\r
- return _iBook.getNameRecord(namePtg.getIndex()).getNameText();\r
- }\r
- public EvaluationName getName(NamePtg namePtg) {\r
- int ix = namePtg.getIndex();\r
- return new Name(_iBook.getNameRecord(ix), ix);\r
- }\r
- public Ptg[] getFormulaTokens(EvaluationCell evalCell) {\r
- HSSFCell cell = ((HSSFEvaluationCell)evalCell).getHSSFCell();\r
- if (false) {\r
- // re-parsing the formula text also works, but is a waste of time\r
- // It is useful from time to time to run all unit tests with this code\r
- // to make sure that all formulas POI can evaluate can also be parsed.\r
- return HSSFFormulaParser.parse(cell.getCellFormula(), _uBook);\r
- }\r
- FormulaRecordAggregate fra = (FormulaRecordAggregate) cell.getCellValueRecord();\r
- return fra.getFormulaTokens();\r
- }\r
-\r
- private static final class Name implements EvaluationName {\r
-\r
- private final NameRecord _nameRecord;\r
- private final int _index;\r
-\r
- public Name(NameRecord nameRecord, int index) {\r
- _nameRecord = nameRecord;\r
- _index = index;\r
- }\r
- public Ptg[] getNameDefinition() {\r
- return _nameRecord.getNameDefinition();\r
- }\r
- public String getNameText() {\r
- return _nameRecord.getNameText();\r
- }\r
- public boolean hasFormula() {\r
- return _nameRecord.hasFormula();\r
- }\r
- public boolean isFunctionName() {\r
- return _nameRecord.isFunctionName();\r
- }\r
- public boolean isRange() {\r
- return _nameRecord.hasFormula(); // TODO - is this right?\r
- }\r
- public NamePtg createPtg() {\r
- return new NamePtg(_index);\r
- }\r
- }\r
+ private final HSSFWorkbook _uBook;\r
+ private final Workbook _iBook;\r
+\r
+ public static HSSFEvaluationWorkbook create(HSSFWorkbook book) {\r
+ if (book == null) {\r
+ return null;\r
+ }\r
+ return new HSSFEvaluationWorkbook(book);\r
+ }\r
+\r
+ private HSSFEvaluationWorkbook(HSSFWorkbook book) {\r
+ _uBook = book;\r
+ _iBook = book.getWorkbook();\r
+ }\r
+\r
+ public int getExternalSheetIndex(String sheetName) {\r
+ int sheetIndex = _uBook.getSheetIndex(sheetName);\r
+ return _iBook.checkExternSheet(sheetIndex);\r
+ }\r
+ public int getExternalSheetIndex(String workbookName, String sheetName) {\r
+ return _iBook.getExternalSheetIndex(workbookName, sheetName);\r
+ }\r
+\r
+ public NameXPtg getNameXPtg(String name) {\r
+ return _iBook.getNameXPtg(name);\r
+ }\r
+\r
+ /**\r
+ * Lookup a named range by its name.\r
+ *\r
+ * @param name the name to search\r
+ * @param sheetIndex the 0-based index of the sheet this formula belongs to.\r
+ * The sheet index is required to resolve sheet-level names. <code>-1</code> means workbook-global names\r
+ */\r
+ public EvaluationName getName(String name, int sheetIndex) {\r
+ for(int i=0; i < _iBook.getNumNames(); i++) {\r
+ NameRecord nr = _iBook.getNameRecord(i);\r
+ if (nr.getSheetNumber() == sheetIndex+1 && name.equalsIgnoreCase(nr.getNameText())) {\r
+ return new Name(nr, i);\r
+ }\r
+ }\r
+ return sheetIndex == -1 ? null : getName(name, -1);\r
+ }\r
+\r
+ public int getSheetIndex(EvaluationSheet evalSheet) {\r
+ HSSFSheet sheet = ((HSSFEvaluationSheet)evalSheet).getHSSFSheet();\r
+ return _uBook.getSheetIndex(sheet);\r
+ }\r
+ public int getSheetIndex(String sheetName) {\r
+ return _uBook.getSheetIndex(sheetName);\r
+ }\r
+\r
+ public String getSheetName(int sheetIndex) {\r
+ return _uBook.getSheetName(sheetIndex);\r
+ }\r
+\r
+ public EvaluationSheet getSheet(int sheetIndex) {\r
+ return new HSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex));\r
+ }\r
+ public int convertFromExternSheetIndex(int externSheetIndex) {\r
+ return _iBook.getSheetIndexFromExternSheetIndex(externSheetIndex);\r
+ }\r
+\r
+ public ExternalSheet getExternalSheet(int externSheetIndex) {\r
+ return _iBook.getExternalSheet(externSheetIndex);\r
+ }\r
+\r
+ public String resolveNameXText(NameXPtg n) {\r
+ return _iBook.resolveNameXText(n.getSheetRefIndex(), n.getNameIndex());\r
+ }\r
+\r
+ public String getSheetNameByExternSheet(int externSheetIndex) {\r
+ return _iBook.findSheetNameFromExternSheet(externSheetIndex);\r
+ }\r
+ public String getNameText(NamePtg namePtg) {\r
+ return _iBook.getNameRecord(namePtg.getIndex()).getNameText();\r
+ }\r
+ public EvaluationName getName(NamePtg namePtg) {\r
+ int ix = namePtg.getIndex();\r
+ return new Name(_iBook.getNameRecord(ix), ix);\r
+ }\r
+ public Ptg[] getFormulaTokens(EvaluationCell evalCell) {\r
+ HSSFCell cell = ((HSSFEvaluationCell)evalCell).getHSSFCell();\r
+ if (false) {\r
+ // re-parsing the formula text also works, but is a waste of time\r
+ // It is useful from time to time to run all unit tests with this code\r
+ // to make sure that all formulas POI can evaluate can also be parsed.\r
+ return HSSFFormulaParser.parse(cell.getCellFormula(), _uBook, FormulaType.CELL, _uBook.getSheetIndex(cell.getSheet()));\r
+ }\r
+ FormulaRecordAggregate fra = (FormulaRecordAggregate) cell.getCellValueRecord();\r
+ return fra.getFormulaTokens();\r
+ }\r
+\r
+ private static final class Name implements EvaluationName {\r
+\r
+ private final NameRecord _nameRecord;\r
+ private final int _index;\r
+\r
+ public Name(NameRecord nameRecord, int index) {\r
+ _nameRecord = nameRecord;\r
+ _index = index;\r
+ }\r
+ public Ptg[] getNameDefinition() {\r
+ return _nameRecord.getNameDefinition();\r
+ }\r
+ public String getNameText() {\r
+ return _nameRecord.getNameText();\r
+ }\r
+ public boolean hasFormula() {\r
+ return _nameRecord.hasFormula();\r
+ }\r
+ public boolean isFunctionName() {\r
+ return _nameRecord.isFunctionName();\r
+ }\r
+ public boolean isRange() {\r
+ return _nameRecord.hasFormula(); // TODO - is this right?\r
+ }\r
+ public NamePtg createPtg() {\r
+ return new NamePtg(_index);\r
+ }\r
+ }\r
}\r
* @throws IllegalArgumentException if the specified reference is unparsable
*/
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);
}
}
DataValidityTable dvt = sheet.getOrCreateDataValidityTable();
- DVRecord dvRecord = dataValidation.createDVRecord(workbook);
+ DVRecord dvRecord = dataValidation.createDVRecord(this);
dvt.addDataValidation(dvRecord);
}
}
public HSSFSheetConditionalFormatting getSheetConditionalFormatting() {
- return new HSSFSheetConditionalFormatting(workbook, sheet);
+ return new HSSFSheetConditionalFormatting(this);
}
}
*/\r
public final class HSSFSheetConditionalFormatting {\r
\r
- private final HSSFWorkbook _workbook;\r
+ private final HSSFSheet _sheet;\r
private final ConditionalFormattingTable _conditionalFormattingTable;\r
\r
- /* package */ HSSFSheetConditionalFormatting(HSSFWorkbook workbook, Sheet sheet) {\r
- _workbook = workbook;\r
- _conditionalFormattingTable = sheet.getConditionalFormattingTable();\r
- }\r
+ /* package */ HSSFSheetConditionalFormatting(HSSFSheet sheet) {\r
+ _sheet = sheet;\r
+ _conditionalFormattingTable = sheet.getSheet().getConditionalFormattingTable();\r
+ }\r
\r
/**\r
* A factory method allowing to create a conditional formatting rule\r
String formula1,\r
String formula2) {\r
\r
- HSSFWorkbook wb = _workbook;\r
- CFRuleRecord rr = CFRuleRecord.create(wb, comparisonOperation, formula1, formula2);\r
+ HSSFWorkbook wb = _sheet.getWorkbook();\r
+ CFRuleRecord rr = CFRuleRecord.create(_sheet, comparisonOperation, formula1, formula2);\r
return new HSSFConditionalFormattingRule(wb, rr);\r
}\r
\r
* @param formula - formula for the valued, compared with the cell\r
*/\r
public HSSFConditionalFormattingRule createConditionalFormattingRule(String formula) {\r
- HSSFWorkbook wb = _workbook;\r
- CFRuleRecord rr = CFRuleRecord.create(wb, formula);\r
+ HSSFWorkbook wb = _sheet.getWorkbook();\r
+ CFRuleRecord rr = CFRuleRecord.create(_sheet, formula);\r
return new HSSFConditionalFormattingRule(wb, rr);\r
}\r
\r
if (cf == null) {\r
return null;\r
}\r
- return new HSSFConditionalFormatting(_workbook, cf);\r
+ return new HSSFConditionalFormatting(_sheet.getWorkbook(), cf);\r
}\r
\r
/**\r
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.CreationHelper;
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.POILogger;
sb.append("!");
sb.append(parts[i]);
}
- name.setNameDefinition(HSSFFormulaParser.parse(sb.toString(), this));
+ name.setNameDefinition(HSSFFormulaParser.parse(sb.toString(), this, FormulaType.CELL, sheetIndex));
}
/**
private FormulaParsingWorkbook _book;
+ private int _sheetIndex;
/**
* model.Workbook, then use the convenience method on
* usermodel.HSSFFormulaEvaluator
*/
- private FormulaParser(String formula, FormulaParsingWorkbook book){
+ private FormulaParser(String formula, FormulaParsingWorkbook book, int sheetIndex){
_formulaString = formula;
_pointer=0;
_book = book;
_formulaLength = _formulaString.length();
+ _sheetIndex = sheetIndex;
}
public static Ptg[] parse(String formula, FormulaParsingWorkbook book) {
}
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();
return fp.getRPNPtg(formulaType);
}
new FormulaParseException("Name '" + name
+ "' does not look like a cell reference or named range");
}
- EvaluationName evalName = _book.getName(name);
+ EvaluationName evalName = _book.getName(name, _sheetIndex);
if (evalName == null) {
throw new FormulaParseException("Specified named range '"
+ name + "' does not exist in the current workbook.");
// user defined function
// 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) {
nameToken = _book.getNameXPtg(name);
/**\r
* named range name matching is case insensitive\r
*/\r
- EvaluationName getName(String name);\r
+ EvaluationName getName(String name, int sheetIndex);\r
\r
NameXPtg getNameXPtg(String name);\r
\r
throw new IllegalStateException("Shared Formula not found for group index " + idx);
}
String sharedFormula = sfCell.getCTCell().getF().getStringValue();
+ int sheetIndex = sheet.getWorkbook().getSheetIndex(sheet);
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,
getRowIndex() - sfCell.getRowIndex(), getColumnIndex() - sfCell.getColumnIndex());
return FormulaRenderer.toFormulaString(fpb, fmla);
return;
}
- XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(row.getSheet().getWorkbook());
+ XSSFWorkbook wb = row.getSheet().getWorkbook();
+ XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
try {
- Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.CELL);
+ Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.CELL, wb.getSheetIndex(getSheet()));
} catch (RuntimeException e) {
if (e.getClass().getName().startsWith(FormulaParser.class.getName())) {
throw new IllegalArgumentException("Unparsable formula '" + formula + "'", e);
import org.apache.poi.hssf.record.formula.NamePtg;\r
import org.apache.poi.hssf.record.formula.NameXPtg;\r
import org.apache.poi.hssf.record.formula.Ptg;\r
-import org.apache.poi.ss.formula.EvaluationCell;\r
-import org.apache.poi.ss.formula.EvaluationName;\r
-import org.apache.poi.ss.formula.EvaluationSheet;\r
-import org.apache.poi.ss.formula.EvaluationWorkbook;\r
-import org.apache.poi.ss.formula.FormulaParser;\r
-import org.apache.poi.ss.formula.FormulaParsingWorkbook;\r
-import org.apache.poi.ss.formula.FormulaRenderingWorkbook;\r
+import org.apache.poi.ss.formula.*;\r
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;\r
\r
/**\r
return convertToExternalSheetIndex(sheetIndex);\r
}\r
\r
- public EvaluationName getName(String name) {\r
- for(int i=0; i < _uBook.getNumberOfNames(); i++) {\r
- String nameText = _uBook.getNameAt(i).getNameName();\r
- if (name.equalsIgnoreCase(nameText)) {\r
- return new Name(_uBook.getNameAt(i), i, this);\r
- }\r
- }\r
- return null;\r
- }\r
+ public EvaluationName getName(String name, int sheetIndex) {\r
+ for(int i=0; i < _uBook.getNumberOfNames(); i++) {\r
+ XSSFName nm = _uBook.getNameAt(i);\r
+ String nameText = nm.getNameName();\r
+ if (name.equalsIgnoreCase(nameText) && nm.getSheetIndex() == sheetIndex) {\r
+ return new Name(_uBook.getNameAt(i), i, this);\r
+ }\r
+ }\r
+ return sheetIndex == -1 ? null : getName(name, -1);\r
+ }\r
\r
public int getSheetIndex(EvaluationSheet evalSheet) {\r
XSSFSheet sheet = ((XSSFEvaluationSheet)evalSheet).getXSSFSheet();\r
public Ptg[] getFormulaTokens(EvaluationCell evalCell) {\r
XSSFCell cell = ((XSSFEvaluationCell)evalCell).getXSSFCell();\r
XSSFEvaluationWorkbook frBook = XSSFEvaluationWorkbook.create(_uBook);\r
- return FormulaParser.parse(cell.getCellFormula(), frBook);\r
+ return FormulaParser.parse(cell.getCellFormula(), frBook, FormulaType.CELL, _uBook.getSheetIndex(cell.getSheet()));\r
}\r
\r
private static final class Name implements EvaluationName {\r
\r
public Ptg[] getNameDefinition() {\r
\r
- return FormulaParser.parse(_nameRecord.getRefersToFormula(), _fpBook);\r
+ return FormulaParser.parse(_nameRecord.getRefersToFormula(), _fpBook, FormulaType.NAMEDRANGE, _nameRecord.getSheetIndex());\r
}\r
\r
public String getNameText() {\r
public void setRefersToFormula(String formulaText) {
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(workbook);
try {
- Ptg[] ptgs = FormulaParser.parse(formulaText, fpb, FormulaType.NAMEDRANGE);
+ Ptg[] ptgs = FormulaParser.parse(formulaText, fpb, FormulaType.NAMEDRANGE, getSheetIndex());
} catch (RuntimeException e) {
if (e.getClass().getName().startsWith(FormulaParser.class.getName())) {
throw new IllegalArgumentException("Unparsable formula '" + formulaText + "'", e);
assertEquals("B5", cell.getCellFormula());
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());
+ }
+
}
wb.setSheetName(0, "Sheet1");
cell.setCellFormula("Sheet1!B$4:Sheet1!$C1"); // explicit range ':' operator
- assertEquals("Sheet1!B$4:Sheet1!$C1", cell.getCellFormula());
+ assertEquals("Sheet1!B$4:Sheet1!$C1", cell.getCellFormula());
cell.setCellFormula("Sheet1!B$4:$C1"); // plain area ref
assertEquals("Sheet1!B1:$C$4", cell.getCellFormula()); // note - area ref is normalised
-
+
cell.setCellFormula("Sheet1!$C1...B$4"); // different syntax for plain area ref
assertEquals("Sheet1!B1:$C$4", cell.getCellFormula());
assertEquals("'true'!B2", cell.getCellFormula());
}
-
+
public void testParseExternalWorkbookReference() {
HSSFWorkbook wbA = HSSFTestDataSamples.openSampleWorkbook("multibookFormulaA.xls");
HSSFCell cell = wbA.getSheetAt(0).getRow(0).getCell(0);
assertEquals("[multibookFormulaB.xls]BSheet1!B1", cell.getCellFormula());
Ptg[] expectedPtgs = FormulaExtractor.getPtgs(cell);
confirmSingle3DRef(expectedPtgs, 1);
-
+
// now try (re-)parsing the formula
Ptg[] actualPtgs = HSSFFormulaParser.parse("[multibookFormulaB.xls]BSheet1!B1", wbA);
confirmSingle3DRef(actualPtgs, 1); // externalSheetIndex 1 -> BSheet1
-
+
// try parsing a formula pointing to a different external sheet
Ptg[] otherPtgs = HSSFFormulaParser.parse("[multibookFormulaB.xls]AnotherSheet!B1", wbA);
confirmSingle3DRef(otherPtgs, 0); // externalSheetIndex 0 -> AnotherSheet
-
+
// try setting the same formula in a cell
cell.setCellFormula("[multibookFormulaB.xls]AnotherSheet!B1");
assertEquals("[multibookFormulaB.xls]AnotherSheet!B1", cell.getCellFormula());
assertEquals(Ref3DPtg.class, ptg0.getClass());
assertEquals(expectedExternSheetIndex, ((Ref3DPtg)ptg0).getExternSheetIndex());
}
-
+
public void testUnion() {
String formula = "Sheet1!$B$2:$C$3,OFFSET(Sheet1!$E$2:$E$4,1,Sheet1!$A$1),Sheet1!$D$6";
HSSFWorkbook wb = new HSSFWorkbook();
wb.createSheet("Sheet1");
Ptg[] ptgs = FormulaParser.parse(formula, HSSFEvaluationWorkbook.create(wb));
-
+
Class[] expectedClasses = {
// TODO - AttrPtg.class, // Excel prepends this
MemFuncPtg.class,
import org.apache.poi.hssf.record.formula.RefNPtg;
import org.apache.poi.hssf.record.formula.RefPtg;
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.util.LittleEndian;
import org.apache.poi.ss.formula.Formula;
public void testConstructors ()
{
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(ComparisonOperator.NO_COMPARISON, rule1.getComparisonOperation());
assertNotNull(rule1.getParsedExpression1());
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(ComparisonOperator.BETWEEN, rule2.getComparisonOperation());
assertNotNull(rule2.getParsedExpression1());
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(ComparisonOperator.EQUAL, rule3.getComparisonOperation());
assertSame(Ptg.EMPTY_PTG_ARRAY, rule3.getParsedExpression2());
public void testCreateCFRuleRecord ()
{
HSSFWorkbook workbook = new HSSFWorkbook();
- CFRuleRecord record = CFRuleRecord.create(workbook, "7");
+ HSSFSheet sheet = workbook.createSheet();
+ CFRuleRecord record = CFRuleRecord.create(sheet, "7");
testCFRuleRecord(record);
// Serialize
public void testWrite() {
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.setFillPattern(PatternFormatting.BRICKS);
import org.apache.poi.hssf.record.RecordFactory;
import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator;
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.util.LittleEndian;
public void testCFRecordsAggregate()
{
HSSFWorkbook workbook = new HSSFWorkbook();
- List recs = new ArrayList();
+ HSSFSheet sheet = workbook.createSheet();
+
+ List recs = new ArrayList();
CFHeaderRecord header = new CFHeaderRecord();
- CFRuleRecord rule1 = CFRuleRecord.create(workbook, "7");
- CFRuleRecord rule2 = CFRuleRecord.create(workbook, ComparisonOperator.BETWEEN, "2", "5");
- CFRuleRecord rule3 = CFRuleRecord.create(workbook, ComparisonOperator.GE, "100", null);
+ CFRuleRecord rule1 = CFRuleRecord.create(sheet, "7");
+ CFRuleRecord rule2 = CFRuleRecord.create(sheet, ComparisonOperator.BETWEEN, "2", "5");
+ CFRuleRecord rule3 = CFRuleRecord.create(sheet, ComparisonOperator.GE, "100", null);
header.setNumberOfConditionalFormats(3);
CellRangeAddress[] cellRanges = {
new CellRangeAddress(0,1,0,0),
*/
public void testNRules() {
HSSFWorkbook workbook = new HSSFWorkbook();
+ HSSFSheet sheet = workbook.createSheet();
CellRangeAddress[] cellRanges = {
new CellRangeAddress(0,1,0,0),
new CellRangeAddress(0,1,2,2),
};
CFRuleRecord[] rules = {
- CFRuleRecord.create(workbook, "7"),
- CFRuleRecord.create(workbook, ComparisonOperator.BETWEEN, "2", "5"),
+ CFRuleRecord.create(sheet, "7"),
+ CFRuleRecord.create(sheet, ComparisonOperator.BETWEEN, "2", "5"),
};
CFRecordsAggregate agg = new CFRecordsAggregate(cellRanges, rules);
byte[] serializedRecord = new byte[agg.getRecordSize()];
import junit.framework.TestCase;
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.util.TempFile;
+import org.apache.poi.ss.formula.FormulaType;
/**
* @author Andrew C. Oliver (acoliver at apache dot org)
// don't know how to check correct result .. for the moment, we just verify that the file can be read.
for (int x = 1; x < Short.MAX_VALUE && x > 0; x=(short)(x*2)) {
- HSSFRow r = s.getRow(x);
+ HSSFRow r = s.getRow(x);
for (int y = 1; y < 256 && y > 0; y=(short)(y+2)) {
- HSSFCell c = r.getCell(y);
+ HSSFCell c = r.getCell(y);
assertTrue("got a formula",c.getCellFormula()!=null);
assertTrue("loop Formula is as expected "+x+"."+y+operator+y+"."+x+"!="+c.getCellFormula(),(
public void testAbsRefs() {
HSSFWorkbook wb = new HSSFWorkbook();
- HSSFSheet s = wb.createSheet();
- HSSFRow r;
- HSSFCell c;
+ HSSFSheet s = wb.createSheet();
+ HSSFRow r;
+ HSSFCell c;
r = s.createRow(0);
c = r.createCell(0);
assertEquals("DZ2*2", wb.getSheetAt(0).getRow(1).getCell(128).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());
+ }
}
HSSFWorkbook wb = new HSSFWorkbook();
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++) {
assertEquals('R', ptgs[i].getRVAType());
}