]> source.dussan.org Git - poi.git/commitdiff
[github-269] more work on external workbook links (formulas). Thanks to @aspojo....
authorPJ Fanning <fanningpj@apache.org>
Tue, 2 Nov 2021 18:59:18 +0000 (18:59 +0000)
committerPJ Fanning <fanningpj@apache.org>
Tue, 2 Nov 2021 18:59:18 +0000 (18:59 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1894695 13f79535-47bb-0310-9956-ffa450edef68

poi-ooxml/src/main/java/org/apache/poi/xssf/streaming/SXSSFCreationHelper.java
poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFCell.java
poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFCell.java
poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java
poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFFormulaParser.java
poi/src/main/java/org/apache/poi/ss/formula/FormulaParser.java
poi/src/main/java/org/apache/poi/ss/formula/ptg/AreaPtgBase.java
poi/src/main/java/org/apache/poi/ss/formula/ptg/ExternSheetNameResolver.java
poi/src/test/java/org/apache/poi/hssf/model/TestFormulaParser.java

index d18177c03209e606d2a959b2c275d62dcbde6ec3..4095bf78b7ec7b1e7dc1b341bae4aa57769f0712 100644 (file)
@@ -61,6 +61,7 @@ public class SXSSFCreationHelper implements CreationHelper {
 
     @Override
     public SXSSFFormulaEvaluator createFormulaEvaluator() {
+
         return new SXSSFFormulaEvaluator(wb);
     }
 
index a1d33c9600a31462112d085f2ac3aa85eef17b26..d7ed668d1ff6ed9b6ca5778907d81ac643aab94a 100644 (file)
@@ -29,6 +29,7 @@ import org.apache.poi.ss.formula.FormulaRenderer;
 import org.apache.poi.ss.formula.FormulaType;
 import org.apache.poi.ss.formula.SharedFormula;
 import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.ptg.ErrPtg;
 import org.apache.poi.ss.formula.ptg.Ptg;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellBase;
@@ -474,7 +475,19 @@ public final class XSSFCell extends CellBase {
         if (wb.getCellFormulaValidation()) {
             XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
             //validate through the FormulaParser
-            FormulaParser.parse(formula, fpb, formulaType, wb.getSheetIndex(getSheet()), getRowIndex());
+            Ptg[] ptgs = FormulaParser.parse(formula, fpb, formulaType, wb.getSheetIndex(getSheet()), getRowIndex());
+            // Make its format consistent with Excel.
+            // eg: "SUM('Sheet1:Sheet2'!A1:B1)" will be trans to "SUM(Sheet1:Sheet2!A1:B1)"
+            boolean hasError = false;
+            for (Ptg ptg : ptgs) {
+                if (ptg instanceof ErrPtg) {
+                    hasError = true;
+                    break;
+                }
+            }
+            if (!hasError) {
+                formula = FormulaRenderer.toFormulaString(fpb, ptgs);
+            }
         }
 
         CTCellFormula f;
index 54dd5c0b464ca04247523c461f9633bd104e5255..a98f762d7993eab7111e19c67d2a6ae1296ca254 100644 (file)
@@ -563,14 +563,14 @@ public final class TestXSSFCell extends BaseTestXCell {
     @Test
     public final void testCopyCellFrom_CellCopyPolicy_formulaWithUnregisteredUDF() {
         setUp_testCopyCellFrom_CellCopyPolicy();
-
+        // this will format the formula string,
         srcCell.setCellFormula("MYFUNC2(123, $A5, Sheet1!$B7)");
 
         // Copy formula verbatim (no shifting). This is okay because copyCellFrom is Internal.
         // Users should use higher-level copying functions to row- or column-shift formulas.
         final CellCopyPolicy policy = new CellCopyPolicy.Builder().cellFormula(true).build();
         destCell.copyCellFrom(srcCell, policy);
-        assertEquals("MYFUNC2(123, $A5, Sheet1!$B7)", destCell.getCellFormula());
+        assertEquals("MYFUNC2(123,$A5,Sheet1!$B7)", destCell.getCellFormula());
     }
 
     @Test
index 887e23ae11d323cad18a11ed5739d519f2b6d31e..e8f22909351d975694dfa3e75b16080cebd00c0f 100644 (file)
@@ -186,8 +186,8 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator {
                 // Add another formula referencing these workbooks
                 Cell cXSL_cell2 = rXSL.createCell(40);
                 cXSL_cell2.setCellFormula("[56737.xls]Uses!$C$1");
-                // TODO Shouldn't it become [2] like the others?
-                assertEquals("[56737.xls]Uses!$C$1", cXSL_cell2.getCellFormula());
+                // it become [2] like the others
+                assertEquals("[2]Uses!$C$1", cXSL_cell2.getCellFormula());
                 assertEquals("\"Hello!\"", evaluator.evaluate(cXSL_cell2).formatAsString());
 
 
index 7b56cf8965cfa1c42319da9474ee6799a6b3c1f7..9cf439faa991b956b4703fc53526a9810fa35146 100644 (file)
@@ -399,6 +399,51 @@ public final class TestXSSFFormulaParser {
         }
     }
 
+    @Test
+    void testQuotedSheetNamesReference() {
+        // quoted sheet names bug fix
+        Workbook[] wbs = new Workbook[]{new HSSFWorkbook(), new XSSFWorkbook()};
+        for (Workbook wb : wbs) {
+            Sheet sheet1 = wb.createSheet("Sheet1");
+            Sheet sheet2 = wb.createSheet("Sheet2");
+            Sheet sheet3 = wb.createSheet("Sheet 3");
+
+            Row tempRow = sheet1.createRow(0);
+            tempRow.createCell(0).setCellValue(1);
+            tempRow.createCell(1).setCellValue(2);
+
+            tempRow = sheet2.createRow(0);
+            tempRow.createCell(0).setCellValue(3);
+            tempRow.createCell(1).setCellValue(4);
+
+            tempRow = sheet3.createRow(0);
+            tempRow.createCell(0).setCellValue(5);
+            tempRow.createCell(1).setCellValue(6);
+
+            Cell cell = tempRow.createCell(2);
+
+            // unquoted sheet names
+            String formula = "SUM(Sheet1:Sheet2!A1:B1)";
+            cell.setCellFormula(formula);
+            String cellFormula = cell.getCellFormula();
+            assertEquals(formula, cellFormula);
+
+            // quoted sheet names with no space
+            cell = tempRow.createCell(3);
+            formula = "SUM('Sheet1:Sheet2'!A1:B1)";
+            cell.setCellFormula(formula);
+            cellFormula = cell.getCellFormula();
+            assertEquals("SUM(Sheet1:Sheet2!A1:B1)", cellFormula);
+
+            // quoted sheet names with space
+            cell = tempRow.createCell(4);
+            formula = "SUM('Sheet1:Sheet 3'!A1:B1)";
+            cell.setCellFormula(formula);
+            cellFormula = cell.getCellFormula();
+            assertEquals(formula, cellFormula);
+        }
+    }
+
     private static String toFormulaString(Ptg ptg, FormulaParsingWorkbook wb) {
         if (ptg instanceof WorkbookDependentFormula) {
             return ((WorkbookDependentFormula)ptg).toFormulaString((FormulaRenderingWorkbook)wb);
index 94c88219e9b0bc0f0b82ec9391e9eb68734035cf..31649a5d855dbacee3cd4f3aaeb7b6b4571b5c63 100644 (file)
@@ -1171,10 +1171,18 @@ public final class FormulaParser {
             while(!done) {
                 sb.appendCodePoint(look);
                 GetChar();
-                if(look == '\'')
-                {
-                    Match('\'');
-                    done = look != '\'';
+                switch (look){
+                    case '\'' : {
+                        GetChar();
+                        if (look == '\''){
+                            // Any single quotes which were already present in the sheet name will be converted to double single quotes ('')
+                            // so switch back to single quote
+                            GetChar();
+                            break;
+                        }
+                    }
+                    case ':':
+                        done = true;
                 }
             }
 
@@ -1200,6 +1208,9 @@ public final class FormulaParser {
                 sb.appendCodePoint(look);
                 GetChar();
             }
+            if (look == '\'') {
+                GetChar();
+            }
             NameIdentifier iden = new NameIdentifier(sb.toString(), false);
             SkipWhite();
             if (look == '!') {
@@ -1249,6 +1260,7 @@ public final class FormulaParser {
         switch(ch) {
             case '.': // dot is OK
             case '_': // underscore is OK
+            case ' ': // space is OK
                 return true;
         }
         return false;
index 496300720b681a5bfa3d5756c6feabe9e1442302..84cc42c81a2410493b65d20255e532dc879c1eaf 100644 (file)
@@ -290,6 +290,9 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
         if(AreaReference.isWholeColumnReference(SpreadsheetVersion.EXCEL97, topLeft, botRight)) {
             return (new AreaReference(topLeft, botRight, SpreadsheetVersion.EXCEL97)).formatAsString();
         }
+        if (AreaReference.isWholeColumnReference(SpreadsheetVersion.EXCEL2007, topLeft, botRight)){
+            return new AreaReference(topLeft, botRight,SpreadsheetVersion.EXCEL2007).formatAsString();
+        }
         return topLeft.formatAsString() + ":" + botRight.formatAsString();
     }
 
index 3a35909cc2487234e1e2c1b601eabf6c486216da..dd2e2ddf378228cf0e92220e3f8a0736012348e1 100644 (file)
@@ -44,7 +44,16 @@ final class ExternSheetNameResolver {
                 ExternalSheetRange r = (ExternalSheetRange)externalSheet;
                 if (! r.getFirstSheetName().equals(r.getLastSheetName())) {
                     sb.append(':');
-                    SheetNameFormatter.appendFormat(sb, r.getLastSheetName());
+                    // quote should appear at the beginning and end.
+                    StringBuilder temp = new StringBuilder();
+                    SheetNameFormatter.appendFormat(temp, r.getLastSheetName());
+                    char quote = '\'';
+                    if (temp.charAt(0) == quote){
+                        sb.insert(0 , quote);
+                        sb.append(temp.substring(1));
+                    }else {
+                        sb.append(temp);
+                    }
                 }
             }
         } else {
index 6c55d18224f3d335864b52f97b89521028a29c86..0768cd713ef0e70530e496a366f1c4006d5ec675 100644 (file)
@@ -535,9 +535,9 @@ final class TestFormulaParser {
         assertEquals("'Test Sheet'!A1", formula);
 
         // Now both
-        cell.setCellFormula("Cash_Flow:'Test Sheet'!A1");
+        cell.setCellFormula("'Cash_Flow:Test Sheet'!A1");
         formula = cell.getCellFormula();
-        assertEquals("Cash_Flow:'Test Sheet'!A1", formula);
+        assertEquals("'Cash_Flow:Test Sheet'!A1", formula);
 
 
         // References to a range (area) of cells:
@@ -553,9 +553,9 @@ final class TestFormulaParser {
         assertEquals("'Test Sheet'!A1:B2", formula);
 
         // Now both
-        cell.setCellFormula("Cash_Flow:'Test Sheet'!A1:B2");
+        cell.setCellFormula("'Cash_Flow:Test Sheet'!A1:B2");
         formula = cell.getCellFormula();
-        assertEquals("Cash_Flow:'Test Sheet'!A1:B2", formula);
+        assertEquals("'Cash_Flow:Test Sheet'!A1:B2", formula);
 
         wb.close();
     }