fixed evaluation of shared formulas in XSSF, see Bugzilla 49872
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@996265 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
1f6833c72d
commit
0528306b33
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.7-beta3" date="2010-??-??">
|
<release version="3.7-beta3" date="2010-??-??">
|
||||||
|
<action dev="poi-developers" type="fix">49872 - avoid exception in XSSFFormulaEvaluator.evaluateInCell when evaluating shared formulas</action>
|
||||||
<action dev="poi-developers" type="fix">49895 - avoid corruption of XSSFWorkbook after removing all merged cells from sheet</action>
|
<action dev="poi-developers" type="fix">49895 - avoid corruption of XSSFWorkbook after removing all merged cells from sheet</action>
|
||||||
<action dev="poi-developers" type="fix">49907 - fixed inconsistent behaviour between HSSF and XSSF when creating consecutive names</action>
|
<action dev="poi-developers" type="fix">49907 - fixed inconsistent behaviour between HSSF and XSSF when creating consecutive names</action>
|
||||||
<action dev="poi-developers" type="add">Add getMimeType() method to HWPF Picture, alongside existing file extension</action>
|
<action dev="poi-developers" type="add">Add getMimeType() method to HWPF Picture, alongside existing file extension</action>
|
||||||
|
@ -373,20 +373,27 @@ public final class XSSFCell implements Cell {
|
|||||||
/**
|
/**
|
||||||
* Creates a non shared formula from the shared formula counterpart
|
* Creates a non shared formula from the shared formula counterpart
|
||||||
*
|
*
|
||||||
|
* @param si Shared Group Index
|
||||||
* @return non shared formula created for the given shared formula and this cell
|
* @return non shared formula created for the given shared formula and this cell
|
||||||
*/
|
*/
|
||||||
private String convertSharedFormula(int idx){
|
private String convertSharedFormula(int si){
|
||||||
XSSFSheet sheet = getSheet();
|
XSSFSheet sheet = getSheet();
|
||||||
XSSFCell sfCell = sheet.getSharedFormulaCell(idx);
|
|
||||||
if(sfCell == null){
|
CTCellFormula f = sheet.getSharedFormula(si);
|
||||||
throw new IllegalStateException("Shared Formula not found for group index " + idx);
|
if(f == null) throw new IllegalStateException(
|
||||||
}
|
"Master cell of a shared formula with sid="+si+" was not found");
|
||||||
String sharedFormula = sfCell.getCTCell().getF().getStringValue();
|
|
||||||
|
String sharedFormula = f.getStringValue();
|
||||||
|
//Range of cells which the shared formula applies to
|
||||||
|
String sharedFormulaRange = f.getRef();
|
||||||
|
|
||||||
|
CellRangeAddress ref = CellRangeAddress.valueOf(sharedFormulaRange);
|
||||||
|
|
||||||
int sheetIndex = sheet.getWorkbook().getSheetIndex(sheet);
|
int sheetIndex = sheet.getWorkbook().getSheetIndex(sheet);
|
||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(sheet.getWorkbook());
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(sheet.getWorkbook());
|
||||||
Ptg[] ptgs = FormulaParser.parse(sharedFormula, fpb, FormulaType.CELL, sheetIndex);
|
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() - ref.getFirstRow(), getColumnIndex() - ref.getFirstColumn());
|
||||||
return FormulaRenderer.toFormulaString(fpb, fmla);
|
return FormulaRenderer.toFormulaString(fpb, fmla);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,11 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
|
|||||||
private List<XSSFHyperlink> hyperlinks;
|
private List<XSSFHyperlink> hyperlinks;
|
||||||
private ColumnHelper columnHelper;
|
private ColumnHelper columnHelper;
|
||||||
private CommentsTable sheetComments;
|
private CommentsTable sheetComments;
|
||||||
private Map<Integer, XSSFCell> sharedFormulas;
|
/**
|
||||||
|
* cache of master shared formulas in this sheet.
|
||||||
|
* Master shared formula is the first formula in a group of shared formulas is saved in the f element.
|
||||||
|
*/
|
||||||
|
private Map<Integer, CTCellFormula> sharedFormulas;
|
||||||
private List<CellRangeAddress> arrayFormulas;
|
private List<CellRangeAddress> arrayFormulas;
|
||||||
private XSSFDataValidationHelper dataValidationHelper;
|
private XSSFDataValidationHelper dataValidationHelper;
|
||||||
|
|
||||||
@ -168,7 +172,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
|
|||||||
|
|
||||||
private void initRows(CTWorksheet worksheet) {
|
private void initRows(CTWorksheet worksheet) {
|
||||||
_rows = new TreeMap<Integer, XSSFRow>();
|
_rows = new TreeMap<Integer, XSSFRow>();
|
||||||
sharedFormulas = new HashMap<Integer, XSSFCell>();
|
sharedFormulas = new HashMap<Integer, CTCellFormula>();
|
||||||
arrayFormulas = new ArrayList<CellRangeAddress>();
|
arrayFormulas = new ArrayList<CellRangeAddress>();
|
||||||
for (CTRow row : worksheet.getSheetData().getRowList()) {
|
for (CTRow row : worksheet.getSheetData().getRowList()) {
|
||||||
XSSFRow r = new XSSFRow(row, this);
|
XSSFRow r = new XSSFRow(row, this);
|
||||||
@ -2401,12 +2405,12 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a cell holding shared formula by shared group index
|
* Return a master shared formula by index
|
||||||
*
|
*
|
||||||
* @param sid shared group index
|
* @param sid shared group index
|
||||||
* @return a cell holding shared formula or <code>null</code> if not found
|
* @return a CTCellFormula bean holding shared formula or <code>null</code> if not found
|
||||||
*/
|
*/
|
||||||
XSSFCell getSharedFormulaCell(int sid){
|
CTCellFormula getSharedFormula(int sid){
|
||||||
return sharedFormulas.get(sid);
|
return sharedFormulas.get(sid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2415,7 +2419,9 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
|
|||||||
CTCell ct = cell.getCTCell();
|
CTCell ct = cell.getCTCell();
|
||||||
CTCellFormula f = ct.getF();
|
CTCellFormula f = ct.getF();
|
||||||
if (f != null && f.getT() == STCellFormulaType.SHARED && f.isSetRef() && f.getStringValue() != null) {
|
if (f != null && f.getT() == STCellFormulaType.SHARED && f.isSetRef() && f.getStringValue() != null) {
|
||||||
sharedFormulas.put((int)f.getSi(), cell);
|
// save a detached copy to avoid XmlValueDisconnectedException,
|
||||||
|
// this may happen when the master cell of a shared formula is changed
|
||||||
|
sharedFormulas.put((int)f.getSi(), (CTCellFormula)f.copy());
|
||||||
}
|
}
|
||||||
if (f != null && f.getT() == STCellFormulaType.ARRAY && f.getRef() != null) {
|
if (f != null && f.getT() == STCellFormulaType.ARRAY && f.getRef() != null) {
|
||||||
arrayFormulas.add(CellRangeAddress.valueOf(f.getRef()));
|
arrayFormulas.add(CellRangeAddress.valueOf(f.getRef()));
|
||||||
|
@ -32,4 +32,29 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
|
|||||||
public void testSharedFormulas(){
|
public void testSharedFormulas(){
|
||||||
baseTestSharedFormulas("shared_formulas.xlsx");
|
baseTestSharedFormulas("shared_formulas.xlsx");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testSharedFormulas_evaluateInCell(){
|
||||||
|
XSSFWorkbook wb = (XSSFWorkbook)_testDataProvider.openSampleWorkbook("49872.xlsx");
|
||||||
|
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
|
||||||
|
XSSFSheet sheet = wb.getSheetAt(0);
|
||||||
|
|
||||||
|
double result = 3.0;
|
||||||
|
|
||||||
|
// B3 is a master shared formula, C3 and D3 don't have the formula written in their f element.
|
||||||
|
// Instead, the attribute si for a particular cell is used to figure what the formula expression
|
||||||
|
// should be based on the cell's relative location to the master formula, e.g.
|
||||||
|
// B3: <f t="shared" ref="B3:D3" si="0">B1+B2</f>
|
||||||
|
// C3 and D3: <f t="shared" si="0"/>
|
||||||
|
|
||||||
|
// get B3 and evaluate it in the cell
|
||||||
|
XSSFCell b3 = sheet.getRow(2).getCell(1);
|
||||||
|
assertEquals(result, evaluator.evaluateInCell(b3).getNumericCellValue());
|
||||||
|
|
||||||
|
//at this point the master formula is gone, but we are still able to evaluate dependent cells
|
||||||
|
XSSFCell c3 = sheet.getRow(2).getCell(2);
|
||||||
|
assertEquals(result, evaluator.evaluateInCell(c3).getNumericCellValue());
|
||||||
|
|
||||||
|
XSSFCell d3 = sheet.getRow(2).getCell(3);
|
||||||
|
assertEquals(result, evaluator.evaluateInCell(d3).getNumericCellValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user