mirror of https://github.com/apache/poi.git
Areas can have multi-sheet references too, so add FormulaParser support to these as well
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1613437 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
846a1f84a2
commit
f19982e245
|
@ -17,7 +17,9 @@
|
||||||
|
|
||||||
package org.apache.poi.ss.formula.ptg;
|
package org.apache.poi.ss.formula.ptg;
|
||||||
|
|
||||||
|
import org.apache.poi.ss.formula.SheetIdentifier;
|
||||||
import org.apache.poi.ss.formula.SheetNameFormatter;
|
import org.apache.poi.ss.formula.SheetNameFormatter;
|
||||||
|
import org.apache.poi.ss.formula.SheetRangeIdentifier;
|
||||||
import org.apache.poi.ss.util.AreaReference;
|
import org.apache.poi.ss.util.AreaReference;
|
||||||
import org.apache.poi.util.LittleEndianOutput;
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
|
@ -31,21 +33,27 @@ import org.apache.poi.util.LittleEndianOutput;
|
||||||
*/
|
*/
|
||||||
public final class Area3DPxg extends AreaPtgBase implements Pxg {
|
public final class Area3DPxg extends AreaPtgBase implements Pxg {
|
||||||
private int externalWorkbookNumber = -1;
|
private int externalWorkbookNumber = -1;
|
||||||
private String sheetName;
|
private String firstSheetName;
|
||||||
|
private String lastSheetName;
|
||||||
|
|
||||||
public Area3DPxg(int externalWorkbookNumber, String sheetName, String arearef) {
|
public Area3DPxg(int externalWorkbookNumber, SheetIdentifier sheetName, String arearef) {
|
||||||
this(externalWorkbookNumber, sheetName, new AreaReference(arearef));
|
this(externalWorkbookNumber, sheetName, new AreaReference(arearef));
|
||||||
}
|
}
|
||||||
public Area3DPxg(int externalWorkbookNumber, String sheetName, AreaReference arearef) {
|
public Area3DPxg(int externalWorkbookNumber, SheetIdentifier sheetName, AreaReference arearef) {
|
||||||
super(arearef);
|
super(arearef);
|
||||||
this.externalWorkbookNumber = externalWorkbookNumber;
|
this.externalWorkbookNumber = externalWorkbookNumber;
|
||||||
this.sheetName = sheetName;
|
this.firstSheetName = sheetName.getSheetIdentifier().getName();
|
||||||
|
if (sheetName instanceof SheetRangeIdentifier) {
|
||||||
|
this.lastSheetName = ((SheetRangeIdentifier)sheetName).getLastSheetIdentifier().getName();
|
||||||
|
} else {
|
||||||
|
this.lastSheetName = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Area3DPxg(String sheetName, String arearef) {
|
public Area3DPxg(SheetIdentifier sheetName, String arearef) {
|
||||||
this(sheetName, new AreaReference(arearef));
|
this(sheetName, new AreaReference(arearef));
|
||||||
}
|
}
|
||||||
public Area3DPxg(String sheetName, AreaReference arearef) {
|
public Area3DPxg(SheetIdentifier sheetName, AreaReference arearef) {
|
||||||
this(-1, sheetName, arearef);
|
this(-1, sheetName, arearef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +68,10 @@ public final class Area3DPxg extends AreaPtgBase implements Pxg {
|
||||||
sb.append("] ");
|
sb.append("] ");
|
||||||
}
|
}
|
||||||
sb.append("sheet=").append(getSheetName());
|
sb.append("sheet=").append(getSheetName());
|
||||||
|
if (lastSheetName != null) {
|
||||||
|
sb.append(" : ");
|
||||||
|
sb.append("sheet=").append(lastSheetName);
|
||||||
|
}
|
||||||
sb.append(" ! ");
|
sb.append(" ! ");
|
||||||
sb.append(formatReferenceAsString());
|
sb.append(formatReferenceAsString());
|
||||||
sb.append("]");
|
sb.append("]");
|
||||||
|
@ -70,11 +82,17 @@ public final class Area3DPxg extends AreaPtgBase implements Pxg {
|
||||||
return externalWorkbookNumber;
|
return externalWorkbookNumber;
|
||||||
}
|
}
|
||||||
public String getSheetName() {
|
public String getSheetName() {
|
||||||
return sheetName;
|
return firstSheetName;
|
||||||
|
}
|
||||||
|
public String getLastSheetName() {
|
||||||
|
return lastSheetName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSheetName(String sheetName) {
|
public void setSheetName(String sheetName) {
|
||||||
this.sheetName = sheetName;
|
this.firstSheetName = sheetName;
|
||||||
|
}
|
||||||
|
public void setLastSheetName(String sheetName) {
|
||||||
|
this.lastSheetName = sheetName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String format2DRefAsString() {
|
public String format2DRefAsString() {
|
||||||
|
@ -88,7 +106,11 @@ public final class Area3DPxg extends AreaPtgBase implements Pxg {
|
||||||
sb.append(externalWorkbookNumber);
|
sb.append(externalWorkbookNumber);
|
||||||
sb.append(']');
|
sb.append(']');
|
||||||
}
|
}
|
||||||
SheetNameFormatter.appendFormat(sb, sheetName);
|
SheetNameFormatter.appendFormat(sb, firstSheetName);
|
||||||
|
if (lastSheetName != null) {
|
||||||
|
sb.append(':');
|
||||||
|
SheetNameFormatter.appendFormat(sb, lastSheetName);
|
||||||
|
}
|
||||||
sb.append('!');
|
sb.append('!');
|
||||||
sb.append(formatReferenceAsString());
|
sb.append(formatReferenceAsString());
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
|
|
|
@ -81,14 +81,14 @@ public final class Ref3DPxg extends RefPtgBase implements Pxg {
|
||||||
public int getExternalWorkbookNumber() {
|
public int getExternalWorkbookNumber() {
|
||||||
return externalWorkbookNumber;
|
return externalWorkbookNumber;
|
||||||
}
|
}
|
||||||
public String getSheetName() { // TODO Rename to getFirstSheetName
|
public String getSheetName() {
|
||||||
return firstSheetName;
|
return firstSheetName;
|
||||||
}
|
}
|
||||||
public String getLastSheetName() {
|
public String getLastSheetName() {
|
||||||
return lastSheetName;
|
return lastSheetName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSheetName(String sheetName) { // TODO Rename to setFirstSheetName
|
public void setSheetName(String sheetName) {
|
||||||
this.firstSheetName = sheetName;
|
this.firstSheetName = sheetName;
|
||||||
}
|
}
|
||||||
public void setLastSheetName(String sheetName) {
|
public void setLastSheetName(String sheetName) {
|
||||||
|
|
|
@ -200,13 +200,11 @@ public final class XSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Ptg get3DReferencePtg(AreaReference area, SheetIdentifier sheet) {
|
public Ptg get3DReferencePtg(AreaReference area, SheetIdentifier sheet) {
|
||||||
String sheetName = sheet._sheetIdentifier.getName();
|
|
||||||
|
|
||||||
if (sheet._bookName != null) {
|
if (sheet._bookName != null) {
|
||||||
int bookIndex = resolveBookIndex(sheet._bookName);
|
int bookIndex = resolveBookIndex(sheet._bookName);
|
||||||
return new Area3DPxg(bookIndex, sheetName, area);
|
return new Area3DPxg(bookIndex, sheet, area);
|
||||||
} else {
|
} else {
|
||||||
return new Area3DPxg(sheetName, area);
|
return new Area3DPxg(sheet, area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -201,46 +201,46 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
|
||||||
Cell sumF = s1.getRow(2).getCell(0);
|
Cell sumF = s1.getRow(2).getCell(0);
|
||||||
assertNotNull(sumF);
|
assertNotNull(sumF);
|
||||||
assertEquals("SUM(Sheet1:Sheet3!A1)", sumF.getCellFormula());
|
assertEquals("SUM(Sheet1:Sheet3!A1)", sumF.getCellFormula());
|
||||||
assertEquals("66", evaluator.evaluate(sumF).formatAsString());
|
assertEquals("66.0", evaluator.evaluate(sumF).formatAsString());
|
||||||
|
|
||||||
|
|
||||||
// Various Stats formulas on numbers
|
// Various Stats formulas on numbers
|
||||||
Cell avgF = s1.getRow(2).getCell(1);
|
Cell avgF = s1.getRow(2).getCell(1);
|
||||||
assertNotNull(avgF);
|
assertNotNull(avgF);
|
||||||
assertEquals("AVERAGE(Sheet1:Sheet3!A1)", avgF.getCellFormula());
|
assertEquals("AVERAGE(Sheet1:Sheet3!A1)", avgF.getCellFormula());
|
||||||
assertEquals("22", evaluator.evaluate(avgF).formatAsString());
|
assertEquals("22.0", evaluator.evaluate(avgF).formatAsString());
|
||||||
|
|
||||||
Cell minF = s1.getRow(3).getCell(1);
|
Cell minF = s1.getRow(3).getCell(1);
|
||||||
assertNotNull(minF);
|
assertNotNull(minF);
|
||||||
assertEquals("MIX(Sheet1:Sheet3!A$1)", minF.getCellFormula());
|
assertEquals("MIX(Sheet1:Sheet3!A$1)", minF.getCellFormula());
|
||||||
assertEquals("11", evaluator.evaluate(minF).formatAsString());
|
assertEquals("11.0", evaluator.evaluate(minF).formatAsString());
|
||||||
|
|
||||||
Cell maxF = s1.getRow(4).getCell(1);
|
Cell maxF = s1.getRow(4).getCell(1);
|
||||||
assertNotNull(maxF);
|
assertNotNull(maxF);
|
||||||
assertEquals("MAX(Sheet1:Sheet3!A$1)", maxF.getCellFormula());
|
assertEquals("MAX(Sheet1:Sheet3!A$1)", maxF.getCellFormula());
|
||||||
assertEquals("33", evaluator.evaluate(maxF).formatAsString());
|
assertEquals("33.0", evaluator.evaluate(maxF).formatAsString());
|
||||||
|
|
||||||
Cell countF = s1.getRow(5).getCell(1);
|
Cell countF = s1.getRow(5).getCell(1);
|
||||||
assertNotNull(countF);
|
assertNotNull(countF);
|
||||||
assertEquals("COUNT(Sheet1:Sheet3!A$1)", countF.getCellFormula());
|
assertEquals("COUNT(Sheet1:Sheet3!A$1)", countF.getCellFormula());
|
||||||
assertEquals("3", evaluator.evaluate(countF).formatAsString());
|
assertEquals("3.0", evaluator.evaluate(countF).formatAsString());
|
||||||
|
|
||||||
|
|
||||||
// Various CountAs on Strings
|
// Various CountAs on Strings
|
||||||
Cell countA_1F = s1.getRow(2).getCell(2);
|
Cell countA_1F = s1.getRow(2).getCell(2);
|
||||||
assertNotNull(countA_1F);
|
assertNotNull(countA_1F);
|
||||||
assertEquals("COUNTA(Sheet1:Sheet3!C1)", countA_1F.getCellFormula());
|
assertEquals("COUNTA(Sheet1:Sheet3!C1)", countA_1F.getCellFormula());
|
||||||
assertEquals("3", evaluator.evaluate(countA_1F).formatAsString());
|
assertEquals("3.0", evaluator.evaluate(countA_1F).formatAsString());
|
||||||
|
|
||||||
Cell countA_2F = s1.getRow(2).getCell(3);
|
Cell countA_2F = s1.getRow(2).getCell(3);
|
||||||
assertNotNull(countA_2F);
|
assertNotNull(countA_2F);
|
||||||
assertEquals("COUNTA(Sheet1:Sheet3!D1)", countA_2F.getCellFormula());
|
assertEquals("COUNTA(Sheet1:Sheet3!D1)", countA_2F.getCellFormula());
|
||||||
assertEquals("0", evaluator.evaluate(countA_2F).formatAsString());
|
assertEquals("0.0", evaluator.evaluate(countA_2F).formatAsString());
|
||||||
|
|
||||||
Cell countA_3F = s1.getRow(2).getCell(4);
|
Cell countA_3F = s1.getRow(2).getCell(4);
|
||||||
assertNotNull(countA_3F);
|
assertNotNull(countA_3F);
|
||||||
assertEquals("COUNTA(Sheet1:Sheet3!E1)", countA_3F.getCellFormula());
|
assertEquals("COUNTA(Sheet1:Sheet3!E1)", countA_3F.getCellFormula());
|
||||||
assertEquals("3", evaluator.evaluate(countA_3F).formatAsString());
|
assertEquals("3.0", evaluator.evaluate(countA_3F).formatAsString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.apache.poi.ss.formula.FormulaParsingWorkbook;
|
||||||
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
|
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
|
||||||
import org.apache.poi.ss.formula.FormulaType;
|
import org.apache.poi.ss.formula.FormulaType;
|
||||||
import org.apache.poi.ss.formula.WorkbookDependentFormula;
|
import org.apache.poi.ss.formula.WorkbookDependentFormula;
|
||||||
|
import org.apache.poi.ss.formula.ptg.Area3DPtg;
|
||||||
import org.apache.poi.ss.formula.ptg.Area3DPxg;
|
import org.apache.poi.ss.formula.ptg.Area3DPxg;
|
||||||
import org.apache.poi.ss.formula.ptg.AreaPtg;
|
import org.apache.poi.ss.formula.ptg.AreaPtg;
|
||||||
import org.apache.poi.ss.formula.ptg.AttrPtg;
|
import org.apache.poi.ss.formula.ptg.AttrPtg;
|
||||||
|
@ -242,7 +243,9 @@ public final class TestXSSFFormulaParser {
|
||||||
/**
|
/**
|
||||||
* A handful of functions (such as SUM, COUNTA, MIN) support
|
* A handful of functions (such as SUM, COUNTA, MIN) support
|
||||||
* multi-sheet references (eg Sheet1:Sheet3!A1 = Cell A1 from
|
* multi-sheet references (eg Sheet1:Sheet3!A1 = Cell A1 from
|
||||||
* Sheets 1 through Sheet 3).
|
* Sheets 1 through Sheet 3) and multi-sheet area references
|
||||||
|
* (eg Sheet1:Sheet3!A1:B2 = Cells A1 through B2 from Sheets
|
||||||
|
* 1 through Sheet 3).
|
||||||
* This test, based on common test files for HSSF and XSSF, checks
|
* This test, based on common test files for HSSF and XSSF, checks
|
||||||
* that we can read and parse these kinds of references
|
* that we can read and parse these kinds of references
|
||||||
* (but not evaluate - that's elsewhere in the test suite)
|
* (but not evaluate - that's elsewhere in the test suite)
|
||||||
|
@ -274,6 +277,24 @@ public final class TestXSSFFormulaParser {
|
||||||
assertNotNull(maxF);
|
assertNotNull(maxF);
|
||||||
assertEquals("MAX(Sheet1:Sheet3!A$1)", maxF.getCellFormula());
|
assertEquals("MAX(Sheet1:Sheet3!A$1)", maxF.getCellFormula());
|
||||||
|
|
||||||
|
|
||||||
|
Cell sumFA = s1.getRow(2).getCell(7);
|
||||||
|
assertNotNull(sumFA);
|
||||||
|
assertEquals("SUM(Sheet1:Sheet3!A1:B2)", sumFA.getCellFormula());
|
||||||
|
|
||||||
|
Cell avgFA = s1.getRow(2).getCell(8);
|
||||||
|
assertNotNull(avgFA);
|
||||||
|
assertEquals("AVERAGE(Sheet1:Sheet3!A1:B2)", avgFA.getCellFormula());
|
||||||
|
|
||||||
|
Cell maxFA = s1.getRow(4).getCell(8);
|
||||||
|
assertNotNull(maxFA);
|
||||||
|
assertEquals("MAX(Sheet1:Sheet3!A$1:B$2)", maxFA.getCellFormula());
|
||||||
|
|
||||||
|
Cell countFA = s1.getRow(5).getCell(8);
|
||||||
|
assertNotNull(countFA);
|
||||||
|
assertEquals("COUNT(Sheet1:Sheet3!$A$1:$B$2)", countFA.getCellFormula());
|
||||||
|
|
||||||
|
|
||||||
// Create a formula parser
|
// Create a formula parser
|
||||||
FormulaParsingWorkbook fpb = null;
|
FormulaParsingWorkbook fpb = null;
|
||||||
if (wb instanceof HSSFWorkbook)
|
if (wb instanceof HSSFWorkbook)
|
||||||
|
@ -324,10 +345,41 @@ public final class TestXSSFFormulaParser {
|
||||||
assertEquals("MIN", toFormulaString(ptgs[1], fpb));
|
assertEquals("MIN", toFormulaString(ptgs[1], fpb));
|
||||||
|
|
||||||
|
|
||||||
// Check we can round-trip - try to set a new one to a new cell
|
// SUM to a range of cells over 3 workbooks
|
||||||
|
ptgs = parse(fpb, "SUM(Sheet1:Sheet3!A1:B2)");
|
||||||
|
assertEquals(2, ptgs.length);
|
||||||
|
if (wb instanceof HSSFWorkbook) {
|
||||||
|
assertEquals(Area3DPtg.class, ptgs[0].getClass());
|
||||||
|
} else {
|
||||||
|
assertEquals(Area3DPxg.class, ptgs[0].getClass());
|
||||||
|
}
|
||||||
|
assertEquals("Sheet1:Sheet3!A1:B2", toFormulaString(ptgs[0], fpb));
|
||||||
|
assertEquals(AttrPtg.class, ptgs[1].getClass());
|
||||||
|
assertEquals("SUM", toFormulaString(ptgs[1], fpb));
|
||||||
|
|
||||||
|
|
||||||
|
// MIN to a range of cells over 3 workbooks, absolute reference
|
||||||
|
ptgs = parse(fpb, "MIN(Sheet1:Sheet3!$A$1:$B$2)");
|
||||||
|
assertEquals(2, ptgs.length);
|
||||||
|
if (wb instanceof HSSFWorkbook) {
|
||||||
|
assertEquals(Area3DPtg.class, ptgs[0].getClass());
|
||||||
|
} else {
|
||||||
|
assertEquals(Area3DPxg.class, ptgs[0].getClass());
|
||||||
|
}
|
||||||
|
assertEquals("Sheet1:Sheet3!$A$1:$B$2", toFormulaString(ptgs[0], fpb));
|
||||||
|
assertEquals(FuncVarPtg.class, ptgs[1].getClass());
|
||||||
|
assertEquals("MIN", toFormulaString(ptgs[1], fpb));
|
||||||
|
|
||||||
|
|
||||||
|
// Check we can round-trip - try to set a new one to a new single cell
|
||||||
Cell newF = s1.getRow(0).createCell(10, Cell.CELL_TYPE_FORMULA);
|
Cell newF = s1.getRow(0).createCell(10, Cell.CELL_TYPE_FORMULA);
|
||||||
newF.setCellFormula("SUM(Sheet2:Sheet3!A1)");
|
newF.setCellFormula("SUM(Sheet2:Sheet3!A1)");
|
||||||
assertEquals("SUM(Sheet2:Sheet3!A1)", newF.getCellFormula());
|
assertEquals("SUM(Sheet2:Sheet3!A1)", newF.getCellFormula());
|
||||||
|
|
||||||
|
// Check we can round-trip - try to set a new one to a cell range
|
||||||
|
newF = s1.getRow(0).createCell(11, Cell.CELL_TYPE_FORMULA);
|
||||||
|
newF.setCellFormula("MIN(Sheet1:Sheet2!A1:B2)");
|
||||||
|
assertEquals("MIN(Sheet1:Sheet2!A1:B2)", newF.getCellFormula());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static String toFormulaString(Ptg ptg, FormulaParsingWorkbook wb) {
|
private static String toFormulaString(Ptg ptg, FormulaParsingWorkbook wb) {
|
||||||
|
|
|
@ -465,6 +465,9 @@ public final class TestFormulaParser extends TestCase {
|
||||||
HSSFCell cell = row.createCell(0);
|
HSSFCell cell = row.createCell(0);
|
||||||
String formula = null;
|
String formula = null;
|
||||||
|
|
||||||
|
|
||||||
|
// References to a single cell:
|
||||||
|
|
||||||
// One sheet
|
// One sheet
|
||||||
cell.setCellFormula("Cash_Flow!A1");
|
cell.setCellFormula("Cash_Flow!A1");
|
||||||
formula = cell.getCellFormula();
|
formula = cell.getCellFormula();
|
||||||
|
@ -479,6 +482,24 @@ public final class TestFormulaParser extends TestCase {
|
||||||
cell.setCellFormula("Cash_Flow:\'Test Sheet\'!A1");
|
cell.setCellFormula("Cash_Flow:\'Test Sheet\'!A1");
|
||||||
formula = cell.getCellFormula();
|
formula = cell.getCellFormula();
|
||||||
assertEquals("Cash_Flow:\'Test Sheet\'!A1", formula);
|
assertEquals("Cash_Flow:\'Test Sheet\'!A1", formula);
|
||||||
|
|
||||||
|
|
||||||
|
// References to a range (area) of cells:
|
||||||
|
|
||||||
|
// One sheet
|
||||||
|
cell.setCellFormula("Cash_Flow!A1:B2");
|
||||||
|
formula = cell.getCellFormula();
|
||||||
|
assertEquals("Cash_Flow!A1:B2", formula);
|
||||||
|
|
||||||
|
// Then the other
|
||||||
|
cell.setCellFormula("\'Test Sheet\'!A1:B2");
|
||||||
|
formula = cell.getCellFormula();
|
||||||
|
assertEquals("\'Test Sheet\'!A1:B2", formula);
|
||||||
|
|
||||||
|
// Now both
|
||||||
|
cell.setCellFormula("Cash_Flow:\'Test Sheet\'!A1:B2");
|
||||||
|
formula = cell.getCellFormula();
|
||||||
|
assertEquals("Cash_Flow:\'Test Sheet\'!A1:B2", formula);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue