2015-04-16 16 views
8

Sto usando POI 3.12-beta1:XSSF (POI) - Aggiunta colonna "formula" per ruotare tavolo

<!-- Apache POI (for Excel) --> 
<dependency> 
    <groupId>org.apache.poi</groupId> 
    <artifactId>poi</artifactId> 
    <version>3.12-beta1</version> 
</dependency> 

<dependency> 
    <groupId>org.apache.poi</groupId> 
    <artifactId>poi-ooxml</artifactId> 
    <version>3.12-beta1</version> 
</dependency> 

<dependency> 
    <groupId>org.apache.poi</groupId> 
    <artifactId>ooxml-schemas</artifactId> 
    <version>1.1</version> 
</dependency> 

Sto cercando di creare una colonna tabella pivot calcolata che è definita come: = 'Ended'/'Generated' * 100.

sono andato avanti e manualmente modificato il foglio in Excel per ottenere questo lavoro, e quando ho invertito il file *.xlsx in una directory ZIP e guardato attraverso di essa, ho trovato il seguente codice nel \xl\pivotCache\pivotCacheDefinition1.xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<pivotCacheDefinition xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:id="rId1" refreshOnLoad="1" refreshedBy="vyasrav" refreshedDate="42110.580247453705" createdVersion="3" refreshedVersion="3" minRefreshableVersion="3" recordCount="352"> 
    <cacheSource type="worksheet"> 
     <worksheetSource ref="A1:O353" sheet="Data"/> 
    </cacheSource> 
    <cacheFields count="16"> 
     <!-- OMITTED --> 
     <cacheField name="Avg Pct Processed" numFmtId="0" formula="'Ended'/'Generated' * 100" databaseField="0"/> 
    </cacheFields> 
</pivotCacheDefinition> 

così sono tornato al mio programma Java e ha aggiunto il seguente codice per generare automaticamente, ma non è la registrazione colonna di dati "15" e sto ottenendo un errore IndexOutOfBounds.

// Add pivot (pivot table): 
Sheet pivotSheet = workbook.createSheet("Pivot"); 
LOGGER.trace("Created sheet: '" + String.valueOf(pivotSheet) + "'."); 

XSSFPivotTable pivotTable = ((XSSFSheet)pivotSheet).createPivotTable(new AreaReference(tableRange), new CellReference("A1"), dataSheet); 
CTPivotTableDefinition ctPivotTableDefinition = pivotTable.getCTPivotTableDefinition(); 
CTPivotTableStyle ctPivotTableStyle = ctPivotTableDefinition.getPivotTableStyleInfo(); 
ctPivotTableStyle.setName("PivotStyleMedium4"); 

// Row Labels: 
pivotTable.addRowLabel(...); // ... 
... 

// Add column 15 (this is a calculated column): 
CTCacheFields ctCacheFields = pivotTable.getPivotCacheDefinition().getCTPivotCacheDefinition().getCacheFields(); 
CTCacheField ctCacheField = ctCacheFields.addNewCacheField(); 
ctCacheField.setName("Avg Pct Processed"); 
ctCacheField.setFormula("'Ended'/'Generated' * 100"); 

// Column Labels: 
pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 8, "Sum of Generated"); 
pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 12, "Sum of Ended"); 
pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 13, "Sum of Unended"); 
pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 15, "Average of Processed Percent"); 
... 

La StackTrace del IndexOutOfBoundsException che si verifica sulla linea in grassetto sopra è:

Exception in thread "main" java.lang.IndexOutOfBoundsException 
    at org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTPivotFieldsImpl.setPivotFieldArray(Unknown Source) 
    at org.apache.poi.xssf.usermodel.XSSFPivotTable.addDataColumn(XSSFPivotTable.java:372) 
    at org.apache.poi.xssf.usermodel.XSSFPivotTable.addColumnLabel(XSSFPivotTable.java:296) 
    at com...

Qualcuno sa come posso utilizzare POI per generare questa colonna?

EDIT:

Ho provato ad utilizzare entrambe le cose:

CTPivotTableDefinition ctPivotTableDefinition = pivotTable.getCTPivotTableDefinition(); 

e

CTCacheField ctCacheField = ctCacheFields.insertNewCacheField(15); 

e in entrambi i casi, ottengo la stessa eccezione quando questa linea esegue:

pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 15, "Average of Processed Percent"); 
012.351.641,061 mila

Come nota, ho provato a commentare la riga in cui aggiungo la nuova etichetta di colonna e quando lo faccio, se apro la cartella di lavoro in Excel 2010, visualizzo il seguente messaggio di errore all'avvio:

Removed Feature: PivotTable report from /xl/pivotTables/pivotTable1.xml part (PivotTable view) 
Removed Records: Workbook properties from /xl/workbook.xml part (Workbook)

Grazie!

+1

Hai provato insertNewCacheField (int i); – cronos2546

+0

@ cronos2546: Grazie per il suggerimento, ho cambiato la linea nel mio codice di cui sopra: 'CTCacheField ctCacheField = ctCacheFields.addNewCacheField();' a 'CTCacheField ctCacheField = ctCacheFields.insertNewCacheField (15);', ma ancora sto ottenendo lo stesso 'java.lang.IndexOutOfBoundsException' a' at org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTPivotFieldsImpl.setPivotFieldArray (sorgente sconosciuta) 'quando lo script tenta di richiamare:' pivotTable.addColumnLabel (DataConsolidateFunction.SUM, 15, "Average of Processed Percent"); '. – anonymous

+0

Che dolore. C'è un motivo per cui la tua formula media non ha un "=" in essa? – cronos2546

risposta

4

ho risolto il problema nel modo seguente:

//... get or create pivotTable 

//Use first column as row label 
    pivotTable.addRowLabel(0); 
// 1. Add Formula to cache 
    addFormulaToCache(pivotTable); 
// 2. Add PivotField for Formula column 
    addPivotFieldForNewColumn(pivotTable); 
// 3. Add all column labels before our function.. 
    pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 1); 
    //Set the third column as filter 
    pivotTable.addColumnLabel(DataConsolidateFunction.AVERAGE, 2); 
// 4. Add formula column 
    addFormulaColumn(pivotTable); 

Ecco applicazione di metodi:

private static void addFormulaToCache(XSSFPivotTable pivotTable) { 
    CTCacheFields ctCacheFields = pivotTable.getPivotCacheDefinition().getCTPivotCacheDefinition().getCacheFields(); 
    CTCacheField ctCacheField = ctCacheFields.addNewCacheField(); 
    ctCacheField.setName("Field1"); // Any field name 
    ctCacheField.setFormula("'Ended'/'Generated' * 100"); 
    ctCacheField.setDatabaseField(false); 
    ctCacheField.setNumFmtId(0); 
    ctCacheFields.setCount(ctCacheFields.sizeOfCacheFieldArray()); //!!! update count of fields directly 
} 

private static void addPivotFieldForNewColumn(XSSFPivotTable pivotTable) { 
    CTPivotField pivotField = pivotTable.getCTPivotTableDefinition().getPivotFields().addNewPivotField(); 
    pivotField.setDataField(true); 
    pivotField.setDragToCol(false); 
    pivotField.setDragToPage(false); 
    pivotField.setDragToRow(false); 
    pivotField.setShowAll(false); 
    pivotField.setDefaultSubtotal(false); 
} 

private static void addFormulaColumn(XSSFPivotTable pivotTable) { 
    CTDataFields dataFields; 
    if(pivotTable.getCTPivotTableDefinition().getDataFields() != null) { 
     dataFields = pivotTable.getCTPivotTableDefinition().getDataFields(); 
    } else { 
     // can be null if we have not added any column labels yet 
     dataFields = pivotTable.getCTPivotTableDefinition().addNewDataFields(); 
    } 
    CTDataField dataField = dataFields.addNewDataField(); 
    dataField.setName("Avg Pct Processed"); 
    // set index of cached field with formula - it is the last one!!! 
    dataField.setFld(pivotTable.getPivotCacheDefinition().getCTPivotCacheDefinition().getCacheFields().getCount()-1); 
    dataField.setBaseItem(0); 
    dataField.setBaseField(0); 
} 
+0

Scusate per la risposta tardiva, ho preso una vacanza e non l'ho visto fino ad ora. Il codice precedente mi ha aiutato ad andare avanti un bel po ', ho ancora un'eccezione di puntatore nullo quando aggiungo la definizione del campo, ma con i metodi sopra (come 'public') in una classe che ho chiamato' XSSFPivotUtils', sono stato in grado di chiamare: 'XSSFPivotUtils.addFormulaToCache (pivotTable," Avg Pct Processed "," 'Ended'/'Generated' * 100 "); XSSFPivotUtils.addPivotFieldForNewColumn (tabella pivot); XSSFPivotUtils.addFormulaColumn (pivotTable, "Avg Pct Processed"); 'per aggiungere la colonna come campo dati selezionabile da aggiungere alla tabella pivot. – anonymous

+0

Nvm, dopo un'ulteriore valutazione vedo che dovrei sostituire la riga con l'eccezione del puntatore nullo 'pivotTable.addColumnLabel (DataConsolidateFunction.SUM, 15," Average of Processed Percent ");' con la nuova funzione 'XSSFPivotUtils.addFormulaColumn (pivotTable, "Average of Processed Percent"); '. Grazie mille per tutto il tuo aiuto con questo! – anonymous

+0

@valerii ryzhuk Ho aggiunto una riga alla tua risposta per formattare la formula in percentuale. Per tentativi ed errori, NumFmtIds 9 ##% e 10 ##. ##% appaiono appropriati per il richiedente. Vorrei sapere che cosa hanno combinato questi numeri magici. – user1361991