2015-04-16 6 views
8

I POI 3,12-Beta1 bin mit:XSSF (POI) - Hinzufügen von "Formel" Spaltentabelle zu schwenken

<!-- 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> 

Ich versuche, eine berechnete Pivot-Tabelle Spalte zu erstellen, die wie folgt definiert ist: = 'Ended'/'Generated' * 100.

Ich ging weiter und manuell das Blatt in Excel bearbeiten diese, zur Arbeit zu kommen und wenn ich die *.xlsx-Datei in ein ZIP-Verzeichnis umgedreht und sah durch sie, fand ich den folgenden Code in \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> 

Also ging ich zurück zu meinem Java-Programm und fügte den folgenden Code hinzu, um es automatisch zu generieren, aber es registriert nicht die Datenspalte "15" und ich erhalte einen IndexOutOfBounds-Fehler.

// 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"); 
... 

Die Stacktrace der IndexOutOfBoundsException, die oben auf der fett gedruckten Linie auftritt:

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...

Wer weiß, wie kann ich POI diese Spalte zu erzeugen, verwenden?

EDIT:

Ich habe versucht, mit beiden:

CTPivotTableDefinition ctPivotTableDefinition = pivotTable.getCTPivotTableDefinition(); 

und

CTCacheField ctCacheField = ctCacheFields.insertNewCacheField(15); 

und in beiden Szenarien, erhalte ich die gleiche Ausnahme, wenn diese Zeile ausführt:

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

Als Anmerkung, ich habe versucht, die Zeile auskommentieren, wo ich die neue Spaltenbeschriftung hinzufügen, und wenn ich dies tun, wenn ich die Arbeitsmappe in Excel 2010 öffne, erhalte ich die folgende Fehlermeldung beim Start:

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

Danke!

+1

Haben Sie versucht, insertNewCacheField (int i); – cronos2546

+0

@ cronos2546: Danke für den Vorschlag, habe ich die Zeile in meinem Code oben geändert: 'CTCacheField ctCacheField = ctCacheFields.addNewCacheField();' zu 'CTCacheField ctCacheField = ctCacheFields.insertNewCacheField (15);', aber ich bekomme immer noch das gleiche 'java.lang.IndexOutOfBoundsException' at' at org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTPivotFieldsImpl.setPivotFieldArray (Unbekannte Quelle) 'wenn das Skript versucht, aufzurufen:' pivotTable.addColumnLabel (DataConsolateFunction.SUM, 15, "Durchschnitt der verarbeiteten Prozent"); '. – anonymous

+0

Was für ein Schmerz. Gibt es einen Grund dafür, dass Ihre Durchschnittsformel kein "=" enthält? – cronos2546

Antwort

4

ich Ihr Problem in der nächsten Weise gelöst:

//... 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); 

Hier ist die Umsetzung von Methoden:

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

Sorry für die späte Antwort, ich habe Urlaub genommen und habe das bis jetzt nicht gesehen. Der obige Code hat mir geholfen, mich etwas vorwärts zu bewegen, ich habe immer noch eine Nullzeiger-Ausnahme beim Hinzufügen der Felddefinition, aber mit den obigen Methoden (als 'public') in einer Klasse namens 'XSSFPivotUtils' konnte ich aufrufen: 'XSSFPivotUtils.addFormulaToCache (pivotTable," Durchschn. Pkt. Verarbeitet "," 'Beendet "/' Generiert '* 100"); XSSFPivotUtils.addPivotFieldForNewColumn (pivotTable); XSSFPivotUtils.addFormulaColumn (pivotTable, "Avg Pct Processed"); 'um die Spalte als auswählbares Datenfeld hinzuzufügen, das zur PivotTable hinzugefügt werden soll. – anonymous

+0

Nvm, nach weiterer Auswertung sehe ich, dass ich die Zeile mit der Nullzeigerausnahme 'pivotTable.addColumnLabel (DataConsolidateFunction.SUM, 15," Average of Processed Percent ") ersetzen soll;' mit der neuen Funktion 'XSSFPivotUtils.addFormulaColumn (pivotTable, "Durchschnitt der verarbeiteten Prozent"); '. Vielen Dank für Ihre Hilfe! – anonymous

+0

@valerii ryzhuk Ich habe Ihrer Antwort eine Zeile hinzugefügt, um die Formel als Prozentsatz zu formatieren. Nach Versuch und Irrtum scheinen NumFmtIds 9 ##% und 10 ##. ##% dem Fragesteller angemessen zu sein. Ich wünschte, ich wüsste, woran diese magischen Zahlen lagen. – user1361991