Pārlūkot izejas kodu

Make intersection formulae work in XSSF. Patch from Matt Hillsdon plus additional tests.

https://bz.apache.org/bugzilla/show_bug.cgi?id=52111

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1696549 13f79535-47bb-0310-9956-ffa450edef68
tags/REL_3_13_FINAL
David North pirms 8 gadiem
vecāks
revīzija
14be991668

+ 43
- 4
src/java/org/apache/poi/ss/formula/FormulaParser.java Parādīt failu

import org.apache.poi.ss.formula.ptg.FuncVarPtg; import org.apache.poi.ss.formula.ptg.FuncVarPtg;
import org.apache.poi.ss.formula.ptg.GreaterEqualPtg; import org.apache.poi.ss.formula.ptg.GreaterEqualPtg;
import org.apache.poi.ss.formula.ptg.GreaterThanPtg; import org.apache.poi.ss.formula.ptg.GreaterThanPtg;
import org.apache.poi.ss.formula.ptg.IntersectionPtg;
import org.apache.poi.ss.formula.ptg.IntPtg; import org.apache.poi.ss.formula.ptg.IntPtg;
import org.apache.poi.ss.formula.ptg.LessEqualPtg; import org.apache.poi.ss.formula.ptg.LessEqualPtg;
import org.apache.poi.ss.formula.ptg.LessThanPtg; import org.apache.poi.ss.formula.ptg.LessThanPtg;
*/ */
private char look; private char look;


/**
* Tracks whether the run of whitespace preceeding "look" could be an
* intersection operator. See GetChar.
*/
private boolean _inIntersection = false;

private FormulaParsingWorkbook _book; private FormulaParsingWorkbook _book;
private SpreadsheetVersion _ssVersion; private SpreadsheetVersion _ssVersion;


fp.parse(); fp.parse();
return fp.getRPNPtg(formulaType); return fp.getRPNPtg(formulaType);
} }
/** Read New Character From Input Stream */ /** Read New Character From Input Stream */
private void GetChar() { private void GetChar() {
// The intersection operator is a space. We track whether the run of
// whitespace preceeding "look" counts as an intersection operator.
if (IsWhite(look)) {
if (look == ' ') {
_inIntersection = true;
}
}
else {
_inIntersection = false;
}
// Check to see if we've walked off the end of the string. // Check to see if we've walked off the end of the string.
if (_pointer > _formulaLength) { if (_pointer > _formulaLength) {
throw new RuntimeException("too far"); throw new RuntimeException("too far");
// Just return if so and reset 'look' to something to keep // Just return if so and reset 'look' to something to keep
// SkipWhitespace from spinning // SkipWhitespace from spinning
look = (char)0; look = (char)0;
_inIntersection = false;
} }
_pointer++; _pointer++;
//System.out.println("Got char: "+ look); //System.out.println("Got char: "+ look);
return parseUnary(true); return parseUnary(true);
case '(': case '(':
Match('('); Match('(');
ParseNode inside = comparisonExpression();
ParseNode inside = unionExpression();
Match(')'); Match(')');
return new ParseNode(ParenthesisPtg.instance, inside); return new ParseNode(ParenthesisPtg.instance, inside);
case '"': case '"':
result = new ParseNode(operator, result, other); result = new ParseNode(operator, result, other);
} }
} }

private ParseNode unionExpression() { private ParseNode unionExpression() {
ParseNode result = comparisonExpression();
ParseNode result = intersectionExpression();
boolean hasUnions = false; boolean hasUnions = false;
while (true) { while (true) {
SkipWhite(); SkipWhite();
case ',': case ',':
GetChar(); GetChar();
hasUnions = true; hasUnions = true;
ParseNode other = comparisonExpression();
ParseNode other = intersectionExpression();
result = new ParseNode(UnionPtg.instance, result, other); result = new ParseNode(UnionPtg.instance, result, other);
continue; continue;
} }
} }
} }


private ParseNode intersectionExpression() {
ParseNode result = comparisonExpression();
boolean hasIntersections = false;
while (true) {
SkipWhite();
if (_inIntersection) {
// Don't getChar() as the space has already been eaten and recorded by SkipWhite().
hasIntersections = true;
ParseNode other = comparisonExpression();
result = new ParseNode(IntersectionPtg.instance, result, other);
continue;
}
if (hasIntersections) {
return augmentWithMemPtg(result);
}
return result;
}
}
private ParseNode comparisonExpression() { private ParseNode comparisonExpression() {
ParseNode result = concatExpression(); ParseNode result = concatExpression();
while (true) { while (true) {

+ 3
- 1
src/java/org/apache/poi/ss/formula/OperandClassTransformer.java Parādīt failu

import org.apache.poi.ss.formula.ptg.AttrPtg; import org.apache.poi.ss.formula.ptg.AttrPtg;
import org.apache.poi.ss.formula.ptg.ControlPtg; import org.apache.poi.ss.formula.ptg.ControlPtg;
import org.apache.poi.ss.formula.ptg.FuncVarPtg; import org.apache.poi.ss.formula.ptg.FuncVarPtg;
import org.apache.poi.ss.formula.ptg.IntersectionPtg;
import org.apache.poi.ss.formula.ptg.MemAreaPtg; import org.apache.poi.ss.formula.ptg.MemAreaPtg;
import org.apache.poi.ss.formula.ptg.MemFuncPtg; import org.apache.poi.ss.formula.ptg.MemFuncPtg;
import org.apache.poi.ss.formula.ptg.Ptg; import org.apache.poi.ss.formula.ptg.Ptg;
if (token instanceof ValueOperatorPtg || token instanceof ControlPtg if (token instanceof ValueOperatorPtg || token instanceof ControlPtg
|| token instanceof MemFuncPtg || token instanceof MemFuncPtg
|| token instanceof MemAreaPtg || token instanceof MemAreaPtg
|| token instanceof UnionPtg) {
|| token instanceof UnionPtg
|| token instanceof IntersectionPtg) {
// Value Operator Ptgs and Control are base tokens, so token will be unchanged // Value Operator Ptgs and Control are base tokens, so token will be unchanged
// but any child nodes are processed according to desiredOperandClass and callerForceArrayFlag // but any child nodes are processed according to desiredOperandClass and callerForceArrayFlag



+ 26
- 0
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java Parādīt failu

XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("57181.xlsm"); XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("57181.xlsm");
assertEquals(9, wb.getNumberOfSheets()); assertEquals(9, wb.getNumberOfSheets());
} }
@Test
public void bug52111() throws Exception {
Workbook wb = XSSFTestDataSamples.openSampleWorkbook("Intersection-52111-xssf.xlsx");
Sheet s = wb.getSheetAt(0);
assertFormula(wb, s.getRow(2).getCell(0), "(C2:D3 D3:E4)", "4.0");
assertFormula(wb, s.getRow(6).getCell(0), "Tabelle2!E:E Tabelle2!11:11", "5.0");
assertFormula(wb, s.getRow(8).getCell(0), "Tabelle2!E:F Tabelle2!11:12", null);
}
private void assertFormula(Workbook wb, Cell intF, String expectedFormula, String expectedResultOrNull) {
assertEquals(Cell.CELL_TYPE_FORMULA, intF.getCellType());
if (null == expectedResultOrNull) {
assertEquals(Cell.CELL_TYPE_ERROR, intF.getCachedFormulaResultType());
expectedResultOrNull = "#VALUE!";
}
else {
assertEquals(Cell.CELL_TYPE_NUMERIC, intF.getCachedFormulaResultType());
}
assertEquals(expectedFormula, intF.getCellFormula());

// Check we can evaluate it correctly
FormulaEvaluator eval = wb.getCreationHelper().createFormulaEvaluator();
assertEquals(expectedResultOrNull, eval.evaluate(intF).formatAsString());
}
} }

+ 57
- 1
src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java Parādīt failu

assertEquals("IF(1<2,SUM(5,2,IF(3>2,SUM(A1:A2),6)),4)", formulaString); assertEquals("IF(1<2,SUM(5,2,IF(3>2,SUM(A1:A2),6)),4)", formulaString);
} }
public void testParserErrors() { public void testParserErrors() {
parseExpectedException("1 2");
parseExpectedException(" 12 . 345 "); parseExpectedException(" 12 . 345 ");
parseExpectedException("1 .23 "); parseExpectedException("1 .23 ");


); );
MemFuncPtg mf = (MemFuncPtg)ptgs[0]; MemFuncPtg mf = (MemFuncPtg)ptgs[0];
assertEquals(45, mf.getLenRefSubexpression()); assertEquals(45, mf.getLenRefSubexpression());

// We don't check the type of the operands.
confirmTokenClasses("1,2", MemAreaPtg.class, IntPtg.class, IntPtg.class, UnionPtg.class);
} }


public void testIntersection() {
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), FormulaType.CELL, -1);

confirmTokenClasses(ptgs,
// TODO - AttrPtg.class, // Excel prepends this
MemFuncPtg.class,
Area3DPtg.class,
Area3DPtg.class,
IntPtg.class,
Ref3DPtg.class,
FuncVarPtg.class,
IntersectionPtg.class,
Ref3DPtg.class,
IntersectionPtg.class
);
MemFuncPtg mf = (MemFuncPtg)ptgs[0];
assertEquals(45, mf.getLenRefSubexpression());

// This used to be an error but now parses. Union has the same behaviour.
confirmTokenClasses("1 2", MemAreaPtg.class, IntPtg.class, IntPtg.class, IntersectionPtg.class);
}
public void testComparisonInParen() {
confirmTokenClasses("(A1 > B2)",
RefPtg.class,
RefPtg.class,
GreaterThanPtg.class,
ParenthesisPtg.class
);
}
public void testUnionInParen() {
confirmTokenClasses("(A1:B2,B2:C3)",
MemAreaPtg.class,
AreaPtg.class,
AreaPtg.class,
UnionPtg.class,
ParenthesisPtg.class
);
}

public void testIntersectionInParen() {
confirmTokenClasses("(A1:B2 B2:C3)",
MemAreaPtg.class,
AreaPtg.class,
AreaPtg.class,
IntersectionPtg.class,
ParenthesisPtg.class
);
}
public void testRange_bug46643() { public void testRange_bug46643() {
String formula = "Sheet1!A1:Sheet1!B3"; String formula = "Sheet1!A1:Sheet1!B3";
HSSFWorkbook wb = new HSSFWorkbook(); HSSFWorkbook wb = new HSSFWorkbook();

+ 16
- 7
src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java Parādīt failu

public void bug52111() throws Exception { public void bug52111() throws Exception {
Workbook wb = openSample("Intersection-52111.xls"); Workbook wb = openSample("Intersection-52111.xls");
Sheet s = wb.getSheetAt(0); Sheet s = wb.getSheetAt(0);

// Check we can read it correctly
Cell intF = s.getRow(2).getCell(0);
assertFormula(wb, s.getRow(2).getCell(0), "(C2:D3 D3:E4)", "4.0");
assertFormula(wb, s.getRow(6).getCell(0), "Tabelle2!E:E Tabelle2!$A11:$IV11", "5.0");
assertFormula(wb, s.getRow(8).getCell(0), "Tabelle2!E:F Tabelle2!$A11:$IV12", null);
}
private void assertFormula(Workbook wb, Cell intF, String expectedFormula, String expectedResultOrNull) {
assertEquals(Cell.CELL_TYPE_FORMULA, intF.getCellType()); assertEquals(Cell.CELL_TYPE_FORMULA, intF.getCellType());
assertEquals(Cell.CELL_TYPE_NUMERIC, intF.getCachedFormulaResultType());

assertEquals("(C2:D3 D3:E4)", intF.getCellFormula());
if (null == expectedResultOrNull) {
assertEquals(Cell.CELL_TYPE_ERROR, intF.getCachedFormulaResultType());
expectedResultOrNull = "#VALUE!";
}
else {
assertEquals(Cell.CELL_TYPE_NUMERIC, intF.getCachedFormulaResultType());
}
assertEquals(expectedFormula, intF.getCellFormula());


// Check we can evaluate it correctly // Check we can evaluate it correctly
FormulaEvaluator eval = wb.getCreationHelper().createFormulaEvaluator(); FormulaEvaluator eval = wb.getCreationHelper().createFormulaEvaluator();
assertEquals("4.0", eval.evaluate(intF).formatAsString());
assertEquals(expectedResultOrNull, eval.evaluate(intF).formatAsString());
} }


@Test @Test

Binārs
test-data/spreadsheet/Intersection-52111-xssf.xlsx Parādīt failu


Binārs
test-data/spreadsheet/Intersection-52111.xls Parādīt failu


Notiek ielāde…
Atcelt
Saglabāt