2016-08-01 35 views
1

In den letzten paar Tagen hat mich das verrückt gemacht.FormulaEvaluator.evaluateAll() mit externen Referenzen in Excel-Zellen gibt RuntimeException mit Apache POI zurück

Bitte beachten Sie die zwei Excel-Dateien: a.xlsx und b.xlsx

Hier sind die Codes, die Zellen zu bewerten, in a.xlsx einschließlich der externen Verweis auf b.xlsx sollen.

import java.io.FileInputStream; 
import java.io.IOException; 
import java.util.HashMap; 
import java.util.Map; 
import org.apache.poi.ss.usermodel.FormulaEvaluator; 
import org.apache.poi.xssf.usermodel.XSSFWorkbook; 

public class Test { 

    public static void main(String[] args) { 
     try { 
      FileInputStream file1 = new FileInputStream("C:\\Users\\Abid\\Desktop\\a.xlsx"); 
      FileInputStream file2 = new FileInputStream("C:\\Users\\Abid\\Desktop\\b.xlsx"); 

      XSSFWorkbook workbook1 = new XSSFWorkbook(file1); 
      XSSFWorkbook workbook2 = new XSSFWorkbook(file2); 

      FormulaEvaluator evaluator1 = workbook1.getCreationHelper().createFormulaEvaluator(); 
      FormulaEvaluator evaluator2 = workbook2.getCreationHelper().createFormulaEvaluator(); 

      Map<String, FormulaEvaluator> workbooks = new HashMap<String, FormulaEvaluator>(); 

      workbooks.put("a.xlsx", evaluator1); 
      workbooks.put("b.xlsx", evaluator2); 

      evaluator1.setupReferencedWorkbooks(workbooks); 
      evaluator1.evaluateAll(); 

      file1.close(); 
      file2.close(); 

      workbook1.close(); 
      workbook2.close(); 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

} 

Leider ist das, was ich bei der Ausführung erhalten:

Exception in thread "main" java.lang.RuntimeException: Could not resolve external workbook name 'b.xlsx'. Workbook environment has not been set up. 
    at org.apache.poi.ss.formula.OperationEvaluationContext.createExternSheetRefEvaluator(OperationEvaluationContext.java:113) 
    at org.apache.poi.ss.formula.OperationEvaluationContext.createExternSheetRefEvaluator(OperationEvaluationContext.java:84) 
    at org.apache.poi.ss.formula.OperationEvaluationContext.getRef3DEval(OperationEvaluationContext.java:313) 
    at org.apache.poi.ss.formula.WorkbookEvaluator.getEvalForPtg(WorkbookEvaluator.java:634) 
    at org.apache.poi.ss.formula.WorkbookEvaluator.evaluateFormula(WorkbookEvaluator.java:505) 
    at org.apache.poi.ss.formula.WorkbookEvaluator.evaluateAny(WorkbookEvaluator.java:263) 
    at org.apache.poi.ss.formula.WorkbookEvaluator.evaluate(WorkbookEvaluator.java:205) 
    at org.apache.poi.xssf.usermodel.BaseXSSFFormulaEvaluator.evaluateFormulaCellValue(BaseXSSFFormulaEvaluator.java:189) 
    at org.apache.poi.xssf.usermodel.BaseXSSFFormulaEvaluator.evaluateFormulaCell(BaseXSSFFormulaEvaluator.java:117) 
    at org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.evaluateAllFormulaCells(HSSFFormulaEvaluator.java:346) 
    at org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.evaluateAllFormulaCells(HSSFFormulaEvaluator.java:337) 
    at org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator.evaluateAll(XSSFFormulaEvaluator.java:105) 
    at Test.main(Test.java:28) 
Caused by: org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment$WorkbookNotFoundException: Could not resolve external workbook name 'b.xlsx'. Workbook environment has not been set up. 
    at org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.getWorkbookEvaluator(CollaboratingWorkbooksEnvironment.java:195) 
    at org.apache.poi.ss.formula.WorkbookEvaluator.getOtherWorkbookEvaluator(WorkbookEvaluator.java:156) 
    at org.apache.poi.ss.formula.OperationEvaluationContext.createExternSheetRefEvaluator(OperationEvaluationContext.java:111) 
    ... 12 more 
+1

Ich bin nicht mit Apache-Poi vertraut, aber ich sehe in der Fehlerausgabe "Konnte externen Arbeitsmappen-Namen 'b.xlsx' nicht auflösen. Arbeitsmappe-Umgebung wurde nicht eingerichtet." –

+0

Ich habe die Arbeitsmappenumgebung eingerichtet. – Abid357

+0

Ja, ich verstehe. Viel Glück. –

Antwort

0

Sie müssen Apache POI 3.15 Beta 3 oder neuer, oder ein Nightly Build verwenden/bauen aus dem SVN/Build von git am/nach dem 2016.08.04. Als covered in the Apache POI changelog, war dies ein XSSF spezifische Fehler, der

Mit einem Build/Release mit dem Update in sie anschließend fixiert wurde, wird ein Aufruf an evaluateAll() auf einem XSSFFormulaEvaluator verwenden nun alle referenzierten Arbeitsmappe bereits eingerichtet, so wie HSSF tat die ganze Zeit.

2

Es wird mit HSSF (* .xls) ohne Probleme arbeiten.

Aber Apache Poi ist ein Durcheinander. So wird XSSFFormulaEvaluator.evaluateAll() einfach HSSFFormulaEvaluator.evaluateAllFormulaCells(_book); anrufen. Aber HSSFFormulaEvaluator.evaluateAllFormulaCells(Workbook wb) wird eine neueFormulaEvaluator erstellen, die nicht in der Umgebung beteiligt ist.

Stattdessen sollte es HSSFFormulaEvaluator.evaluateAllFormulaCells(Workbook wb, FormulaEvaluator evaluator) nennen und die FormulaEvaluator übergeben, die bereits innerhalb der Umgebung beteiligt ist. Aber diese Methode ist private.

Glücklicherweise ist es nicht so groß und unabhängig. So können wir diese Methode in unserem Code haben:

import java.io.FileInputStream; 
import java.io.IOException; 
import java.util.HashMap; 
import java.util.Map; 
import org.apache.poi.ss.usermodel.*; 

public class TestEvaluateExtRef { 

    private static void evaluateAllFormulaCells(Workbook wb, FormulaEvaluator evaluator) { 
     for(int i=0; i<wb.getNumberOfSheets(); i++) { 
     Sheet sheet = wb.getSheetAt(i); 

      for(Row r : sheet) { 
       for (Cell c : r) { 
        if (c.getCellType() == Cell.CELL_TYPE_FORMULA) { 
         evaluator.evaluateFormulaCell(c); 
        } 
       } 
      } 
     }   
    } 

    public static void main(String[] args) { 
     try { 

      Workbook workbook1 = WorkbookFactory.create(new FileInputStream("a.xlsx")); 
      Workbook workbook2 = WorkbookFactory.create(new FileInputStream("b.xlsx")); 

      FormulaEvaluator evaluator1 = workbook1.getCreationHelper().createFormulaEvaluator(); 
      FormulaEvaluator evaluator2 = workbook2.getCreationHelper().createFormulaEvaluator(); 

      Map<String, FormulaEvaluator> workbooks = new HashMap<String, FormulaEvaluator>(); 

      workbooks.put("a.xlsx", evaluator1); 
      workbooks.put("b.xlsx", evaluator2); 

      workbook2.getSheetAt(0).getRow(0).getCell(0).setCellValue(new java.util.Random().nextDouble()); 

      evaluator1.setupReferencedWorkbooks(workbooks); 

      //evaluator1.evaluateAll(); 
      evaluateAllFormulaCells(workbook1, evaluator1); 

      System.out.println(workbook1.getSheetAt(0).getRow(0).getCell(0)); 
      System.out.println(workbook1.getSheetAt(0).getRow(0).getCell(0).getNumericCellValue()); 

      workbook1.close(); 
      workbook2.close(); 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

} 
+0

Hier sollte kein Unterschied zwischen HSSF und XSSF bestehen. Wenn Sie in der Lage sind, einen kleinen Junit-Test zu schreiben, der das Problem zeigt, und ihn in den POI-Bugzilla hochladen kann, schaue ich gerne vorbei! – Gagravarr

+0

@Gagravarr: Meine Erklärungen und mein Beispielcode hier zeigt ziemlich klar, wo das Problem liegt. Mit 'evaluator1.evaluateAll();' schlägt es fehl. Mit 'evaluateAllFormulaCells (workbook1, evaluator1); 'funktioniert es. Mit 'a.xls' und' b.xls' funktioniert es auch mit 'evaluator1.evaluateAll();'. –