2016-01-29 23 views
6

Sto cercando di inserire una semplice formula VLookup nel mio file ".xlsx" utilizzando Java e Apache POI.
Questa formula ha il riferimento esterno e NON funziona per me.Java POI XSSF VLookup formula

Quindi, per darvi maggiori dettagli sto usando poi e poi-OOXML versione 3.13 e Excel 2007.
sto mettendo la formula nella cella in questo modo (in cui cellula è una cellula):

cell.setCellType(Cell.CELL_TYPE_FORMULA); 
cell.setCellFormula("StringContainingFormula"); 

E poi valutare la formula, ho provato tre modi diversi ma senza alcuna fortuna. (wb è XSSFWorkbook).

FormulaEvaluator mainWorkbookEvaluator = wb.getCreationHelper().createFormulaEvaluator(); 
Map<String,FormulaEvaluator> workbooks = new HashMap<String, FormulaEvaluator>(); 
workbooks.put("SpreadsheetName.xlsx", mainWorkbookEvaluator); 
mainWorkbookEvaluator.setupReferencedWorkbooks(workbooks); 
mainWorkbookEvaluator.evaluateAll(); 
XSSFEvaluationWorkbook.create(wb); 
Workbook nwb = wb; 
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator(); 
for (Sheet sheet : nwb) { 
    for (Row r : sheet) { 
     for (Cell c : r) { 
      if (c.getCellType() == Cell.CELL_TYPE_FORMULA) { 
       try { 
        //evaluator.evaluateFormulaCell(c); 
        evaluator.evaluate(c); 
       } catch (Exception e) { 
        System.out.println("Error occured in 'EvaluateFormulas' : " + e); 
       } 
      } 
     } 
    } 
} 
XSSFFormulaEvaluator.evaluateAllFormulaCells(wb); 

Il problema è, si scrive in un file Excel e poi durante la valutazione getta errore:

java.lang.IllegalArgumentException: Invalid sheetIndex: -1

Ora, se apro il file di Excel, mi dà avvertimento:

Automatic update of links has been disabled

Se abilito il contenuto, formula mostra il risultato correttamente e se non faccio niente di formula con conseguente #N/A.
Ora se seleziono la cella con la formula al suo interno e fai clic su barra della formula e premi invio di una formula mostra il risultato.

Aggiornamento:

Così, ho disabilitato il messaggio di avviso andando in Opzioni di Excel e ha cominciato a darmi la formula all'interno della cellula.
Ma, quando ho cercato di ottenere il valore del risultato da esso usando

if (cell.getCachedFormulaResultType == Cell.CELL_TYPE_STRING) { 
    System.out.println("Last evaluated as \"" + cell.getRichStringCellValue() + "\""); 
} 

Non è mai mi ha dato la getCachedFormulaResultType come CELL_TYPE_STRING, si ritorna sempre CELL_TYPE_NUMERIC. Dovrebbe restituire il valore di stringa. Sto indicando l'URL e un altro valore (parole separate da "|" - "gatto | cane | uccello").

Apprezzo qualsiasi aiuto/suggerimento.

+0

Probabilmente meglio controllare la [valutazione di formula] (https: // poi. apache.org/spreadsheet/eval.html) documentazione attentamente. Forse qualcosa come 'wb.setForceFormulaRecalculation (true);' ti aiuterà? –

+0

Inoltre, il documento dice di 'createFormulaEvaluator' per i fogli di lavoro cui si fa riferimento. Ad esempio, 'workbooks.put (" input.xls ", WorkbookFactory.create (" c: \ temp \ input22.xls "). GetCreationHelper(). CreateFormulaEvaluator());' –

+0

@Nicholas, grazie mille per i tuoi suggerimenti , ma non ho trovato nulla di simile a 'wb.setForceFormulaRecalculation (true);' e ho già provato il riferimento 'createFormulaEvaluator', ma senza fortuna. – ManishChristian

risposta

0

Quindi, come non ho qualsiasi altra opzione, I HA d copiare i dati di riferimento nella cartella di lavoro principale (so che non è una buona idea, nel caso in cui i dati siano enormi) per far funzionare le cose.
Quindi quello che ho fatto è:

  1. Copiare i dati di riferimento da cartella di lavoro esterno.
  2. Creare un nuovo foglio di lavoro sulla cartella di lavoro principale (in cui è necessario scrivere la formula) e incollare i dati di riferimento.
  3. Ora scrivere la formula e questa volta anziché la cartella di lavoro esterna utilizzare il foglio di lavoro appena creato (con i dati incollati).
    Nota *: È necessario scrivere tutti i dati (comprese le formule) prima di andare a valutare le formule.
  4. cartella di lavoro poi aperto per la lettura se è stata chiusa già e valutare tutte le formule di questo tipo (wb è XSSFWorkbook):

XSSFFormulaEvaluator.evaluateAllFormulaCells(wb);

1

Bene, sembra funzionare. Devi trattare eccellentemente delicatamente; è molto più felice se apri prima la cartella di lavoro esterna, poi la cartella di lavoro principale. Se non lo fai, dà un messaggio sui collegamenti non sicuri, ma a parte questo, tutto sembra a posto. Il valutatore funziona solo su singole celle, quindi dovrai eseguire il ciclo se desideri ricalcolare l'intero foglio di calcolo. Inoltre, il riferimento esterno deve essere già stato collegato da excel, POI non ha ancora implementato quella funzione. Ecco cosa ho messo in github:

// Open workbooks 
    Path pathBook1 = Paths.get("c:/users/karl/scsb/Vlookup/Book1.xlsx"); 
    InputStream is = Files.newInputStream(pathBook1); 
    XSSFWorkbook book1 = new XSSFWorkbook(is); 
    // Add Linked Cell 
    // The workbook must already have been linked to Book2.xlsx by Excel 
    // The linkExternalWorkbook has not yet been implemented: SEE BUG #57184 
    Cell cell = book1.getSheetAt(0).createRow(2).createCell(0); 
    cell.setCellFormula("A2+[Book2.xlsx]Sheet1!A1"); 
    // Create evaluator after the new cell has been added. 
    FormulaEvaluator mainEvaluator = book1.getCreationHelper().createFormulaEvaluator(); 
    XSSFWorkbook book2 = new XSSFWorkbook("c:/users/karl/scsb/Vlookup/Book2.xlsx"); 
    Map<String, FormulaEvaluator> workbooks = new HashMap<String, FormulaEvaluator>(); 
    workbooks.put("Book1.xlsx", mainEvaluator); 
    workbooks.put("Book2.xlsx", book2.getCreationHelper().createFormulaEvaluator()); 
    mainEvaluator.setupReferencedWorkbooks(workbooks); 
// mainEvaluator.evaluateAll();       // doesn't work. 
// XSSFFormulaEvaluator.evaluateAllFormulaCells(book1); // doesn't work. 
    mainEvaluator.evaluateFormulaCell(cell); 
    System.out.println(cell.getNumericCellValue()); 
    book2.close(); 
    // Close and write workbook 1 
    is.close(); 
    OutputStream os = Files.newOutputStream(pathBook1); 
    book1.write(os); 
    os.close(); 
    book1.close(); 
+0

Non funziona per me. Se uso 'setCellFormula' (senza il percorso completo (proprio come hai fatto tu)) prima di aprire la cartella di lavoro" Referenced ", mi dà errore' java.lang.RuntimeException: Book non collegato per nomefile "ReferencedFileName.xlsx" '. E se utilizzo il percorso completo, mi restituisce nuovamente l'errore 'sheetIndex: -1' non valido. – ManishChristian

+0

Come ho già detto, il foglio di calcolo esterno deve essere collegato da Excel prima di eseguire questo codice. C'è una chiamata al metodo per collegare fogli di lavoro in POI ('linkExternalWorkbook'), ma non è implementata. Non c'è nulla che io possa fare al riguardo. –

+0

Prima di tutto, grazie mille @Nicholas per il tuo aiuto. Quindi, nel modo più breve, possiamo dire che questo non è fattibile al momento?Perché se non siamo in grado di collegare le cartelle di lavoro, allora non ha senso fare riferimento alla cartella di lavoro esterna. – ManishChristian

0

Ho lo stesso problema di recente.Il problema era che con l'attuale POI, non si può scrivere un documento, aggiungere la formula a un campo specifico ed eseguire la valutazione della formula su un documento, in questo momento, ancora non esistente. Il trucco che ho usato per risolvere era:

  1. scrivere tutti i dati e le formule in una cartella di lavoro
  2. aggiungere workbook.setForceFormulaRecalculation(true); prima di chiudere questo documento
  3. scrittura e chiudere il documento
  4. Aprire lo stesso documento di nuovo e solo fare FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator(); evaluator.evaluateAll();
  5. scrittura e richiudere
Problemi correlati