* a..b!A1
* 'my sheet'!A1
* .my.sheet!A1
+ * 'my sheet':'my alt sheet'!A1
+ * .my.sheet1:.my.sheet2!$B$2
* my.named..range.
* 'my sheet'!my.named.range
* .my.sheet!my.named.range
SkipWhite();
int savePointer = _pointer;
SheetIdentifier sheetIden = parseSheetName();
+
if (sheetIden == null) {
resetPointer(savePointer);
} else {
GetChar();
return new SheetIdentifier(bookName, iden);
}
+ // See if it's a multi-sheet range, eg Sheet1:Sheet3!A1
+ if (look == ':') {
+ return parseSheetRange(bookName, iden);
+ }
return null;
}
sb.append(look);
GetChar();
}
+ NameIdentifier iden = new NameIdentifier(sb.toString(), false);
SkipWhite();
if (look == '!') {
GetChar();
- return new SheetIdentifier(bookName, new NameIdentifier(sb.toString(), false));
+ return new SheetIdentifier(bookName, iden);
}
+ // See if it's a multi-sheet range, eg Sheet1:Sheet3!A1
+ if (look == ':') {
+ return parseSheetRange(bookName, iden);
+ }
return null;
}
if (look == '!' && bookName != null) {
- // Raw book reference, wihtout a sheet
+ // Raw book reference, without a sheet
GetChar();
return new SheetIdentifier(bookName, null);
}
return null;
}
+
+ /**
+ * If we have something that looks like [book]Sheet1: or
+ * Sheet1, see if it's actually a range eg Sheet1:Sheet2!
+ */
+ private SheetIdentifier parseSheetRange(String bookname, NameIdentifier sheet1Name) {
+ GetChar();
+ SheetIdentifier sheet2 = parseSheetName();
+ if (sheet2 != null) {
+ return new SheetRangeIdentifier(bookname, sheet1Name, sheet2.getSheetIdentifier());
+ }
+ return null;
+ }
/**
* very similar to {@link SheetNameFormatter#isSpecialChar(char)}
--- /dev/null
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.formula;
+
+public class SheetRangeIdentifier extends SheetIdentifier {
+ public NameIdentifier _lastSheetIdentifier;
+
+ public SheetRangeIdentifier(String bookName, NameIdentifier firstSheetIdentifier, NameIdentifier lastSheetIdentifier) {
+ super(bookName, firstSheetIdentifier);
+ _lastSheetIdentifier = lastSheetIdentifier;
+ }
+ public NameIdentifier getFirstSheetIdentifier() {
+ return super.getSheetIdentifier();
+ }
+ public NameIdentifier getLastSheetIdentifier() {
+ return _lastSheetIdentifier;
+ }
+ protected void asFormulaString(StringBuffer sb) {
+ super.asFormulaString(sb);
+ sb.append(':');
+ if (_lastSheetIdentifier.isQuoted()) {
+ sb.append("'").append(_lastSheetIdentifier.getName()).append("'");
+ } else {
+ sb.append(_lastSheetIdentifier.getName());
+ }
+ }
+}
\ No newline at end of file
import org.apache.poi.ss.formula.FormulaParseException;
import org.apache.poi.ss.formula.FormulaParser;
import org.apache.poi.ss.formula.FormulaParsingWorkbook;
+import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
import org.apache.poi.ss.formula.FormulaType;
+import org.apache.poi.ss.formula.WorkbookDependentFormula;
import org.apache.poi.ss.formula.ptg.Area3DPxg;
import org.apache.poi.ss.formula.ptg.AreaPtg;
import org.apache.poi.ss.formula.ptg.AttrPtg;
import org.apache.poi.ss.formula.ptg.NamePtg;
import org.apache.poi.ss.formula.ptg.NameXPxg;
import org.apache.poi.ss.formula.ptg.Ptg;
+import org.apache.poi.ss.formula.ptg.Ref3DPtg;
import org.apache.poi.ss.formula.ptg.Ref3DPxg;
import org.apache.poi.ss.formula.ptg.RefPtg;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.XSSFTestDataSamples;
-import org.junit.Ignore;
import org.junit.Test;
public final class TestXSSFFormulaParser {
* This test, based on common test files for HSSF and XSSF, checks
* that we can read and parse these kinds of references
* (but not evaluate - that's elsewhere in the test suite)
- *
- * DISABLED pending support, see bug #55906
*/
@Test
- @Ignore
public void multiSheetReferencesHSSFandXSSF() throws Exception {
Workbook[] wbs = new Workbook[] {
HSSFTestDataSamples.openSampleWorkbook("55906-MultiSheetRefs.xls"),
else
fpb = XSSFEvaluationWorkbook.create((XSSFWorkbook)wb);
+
// Check things parse as expected:
+ // Note - Ptgs will only show one sheet, the formula
+ // parser stuff looks up the second later
+
// SUM to one cell over 3 workbooks, relative reference
- ptgs = parse(fpb, "SUM(Sheet1:Sheet3!A1");
- // TODO
-// assertEquals(1, ptgs.length);
-// assertEquals(Ref3DPxg.class, ptgs[0].getClass());
+ ptgs = parse(fpb, "SUM(Sheet1:Sheet3!A1)");
+ assertEquals(2, ptgs.length);
+ if (wb instanceof HSSFWorkbook) {
+ assertEquals(Ref3DPtg.class, ptgs[0].getClass());
+ assertEquals("Sheet1!A1", toFormulaString(ptgs[0], fpb));
+ } else {
+ assertEquals(Ref3DPxg.class, ptgs[0].getClass());
+ assertEquals("Sheet1!A1", toFormulaString(ptgs[0], fpb));
+ }
+ assertEquals(AttrPtg.class, ptgs[1].getClass());
+ assertEquals("SUM", toFormulaString(ptgs[1], fpb));
+
// MAX to one cell over 3 workbooks, absolute row reference
- ptgs = parse(fpb, "MAX(Sheet1:Sheet3!A$1");
- // TODO
-// assertEquals(1, ptgs.length);
-// assertEquals(Ref3DPxg.class, ptgs[0].getClass());
+ ptgs = parse(fpb, "MAX(Sheet1:Sheet3!A$1)");
+ assertEquals(2, ptgs.length);
+ if (wb instanceof HSSFWorkbook) {
+ assertEquals(Ref3DPtg.class, ptgs[0].getClass());
+ assertEquals("Sheet1!A$1", toFormulaString(ptgs[0], fpb));
+ } else {
+ assertEquals(Ref3DPxg.class, ptgs[0].getClass());
+ assertEquals("Sheet1!A$1", toFormulaString(ptgs[0], fpb));
+ }
+ assertEquals(FuncVarPtg.class, ptgs[1].getClass());
+ assertEquals("MAX", toFormulaString(ptgs[1], fpb));
+
// MIN to one cell over 3 workbooks, absolute reference
- ptgs = parse(fpb, "MIN(Sheet1:Sheet3!$A$1");
- // TODO
-// assertEquals(1, ptgs.length);
-// assertEquals(Ref3DPxg.class, ptgs[0].getClass());
+ ptgs = parse(fpb, "MIN(Sheet1:Sheet3!$A$1)");
+ assertEquals(2, ptgs.length);
+ if (wb instanceof HSSFWorkbook) {
+ assertEquals(Ref3DPtg.class, ptgs[0].getClass());
+ assertEquals("Sheet1!$A$1", toFormulaString(ptgs[0], fpb));
+ } else {
+ assertEquals(Ref3DPxg.class, ptgs[0].getClass());
+ assertEquals("Sheet1!$A$1", toFormulaString(ptgs[0], fpb));
+ }
+ assertEquals(FuncVarPtg.class, ptgs[1].getClass());
+ assertEquals("MIN", toFormulaString(ptgs[1], fpb));
+ }
+ }
+ private static String toFormulaString(Ptg ptg, FormulaParsingWorkbook wb) {
+ if (ptg instanceof WorkbookDependentFormula) {
+ return ((WorkbookDependentFormula)ptg).toFormulaString((FormulaRenderingWorkbook)wb);
}
+ return ptg.toFormulaString();
}
}
assertEquals("A1:A2", formula);
}
+ public void testMultiSheetReference() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+
+ wb.createSheet("Cash_Flow");
+ wb.createSheet("Test Sheet");
+
+ HSSFSheet sheet = wb.createSheet("Test");
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell = row.createCell(0);
+ String formula = null;
+
+ // One sheet
+ cell.setCellFormula("Cash_Flow!A1");
+ formula = cell.getCellFormula();
+ assertEquals("Cash_Flow!A1", formula);
+
+ // Then the other
+ cell.setCellFormula("\'Test Sheet\'!A1");
+ formula = cell.getCellFormula();
+ assertEquals("\'Test Sheet\'!A1", formula);
+
+ // Now both
+ // TODO Implement remaining logic for #55906
+ cell.setCellFormula("Cash_Flow:\'Test Sheet\'!A1");
+ formula = cell.getCellFormula();
+// assertEquals("Cash_Flow:\'Test Sheet\'!A1", formula);
+ }
+
/**
* Test for bug observable at svn revision 618865 (5-Feb-2008)<br/>
* a formula consisting of a single no-arg function got rendered without the function braces