]> source.dussan.org Git - poi.git/commitdiff
More progress towards #55906 - FormulaParser is able to identify and parse multi...
authorNick Burch <nick@apache.org>
Thu, 24 Jul 2014 22:44:51 +0000 (22:44 +0000)
committerNick Burch <nick@apache.org>
Thu, 24 Jul 2014 22:44:51 +0000 (22:44 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1613317 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/ss/formula/FormulaParser.java
src/java/org/apache/poi/ss/formula/SheetIdentifier.java
src/java/org/apache/poi/ss/formula/SheetRangeIdentifier.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaParser.java
src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java

index 519e08ea715774c4faa96027730f8c57af232d07..1bae4fda3130d7c8e4f9e01253c23c8428d9e5d2 100644 (file)
@@ -366,6 +366,8 @@ public final class FormulaParser {
         *   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
@@ -383,6 +385,7 @@ public final class FormulaParser {
                SkipWhite();
                int savePointer = _pointer;
                SheetIdentifier sheetIden = parseSheetName();
+               
                if (sheetIden == null) {
                        resetPointer(savePointer);
                } else {
@@ -807,6 +810,10 @@ public final class FormulaParser {
                                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;
                }
 
@@ -818,20 +825,38 @@ public final class FormulaParser {
                                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)}
index be5639b37fb13939e7f0cf30a2cfa88ebf330359..71c7cd0f0c88b4d5b51e268f7ed1cbce70d59cda 100644 (file)
@@ -31,7 +31,7 @@ public class SheetIdentifier {
     public NameIdentifier getSheetIdentifier() {
         return _sheetIdentifier;
     }
-    private void asFormulaString(StringBuffer sb) {
+    protected void asFormulaString(StringBuffer sb) {
         if (_bookName != null) {
             sb.append(" [").append(_sheetIdentifier.getName()).append("]");
         }
diff --git a/src/java/org/apache/poi/ss/formula/SheetRangeIdentifier.java b/src/java/org/apache/poi/ss/formula/SheetRangeIdentifier.java
new file mode 100644 (file)
index 0000000..c0b851e
--- /dev/null
@@ -0,0 +1,42 @@
+/* ====================================================================
+   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
index c006227931f31df905a3a3f35c8d1aed3e8d76f5..222da5cd6275a5ed76372d0abcac0905de60141f 100644 (file)
@@ -28,7 +28,9 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 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;
@@ -38,13 +40,13 @@ import org.apache.poi.ss.formula.ptg.IntPtg;
 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 {
@@ -244,11 +246,8 @@ 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"),
@@ -282,25 +281,58 @@ public final class TestXSSFFormulaParser {
             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();
     }
 }
index 59faa04303d4e4ba4d3d68b65c0b8b94f5b3f066..f780bde0e6314892ad75abe372e1d69eae39a528 100644 (file)
@@ -454,6 +454,34 @@ public final class TestFormulaParser extends TestCase {
                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