2016-04-15 30 views
1

我需要一些幫助解決我遇到的問題。 我首先要描述我的問題,然後,如果需要,可以閱讀下面的代碼並查看實現細節。無法在.xlsx代中觸發數據透視表計算

簡短說明: 我生成包含2片Excel工作簿:

表1:通用數據。

表2:通用數據透視表。

因爲一些Apache提供的POI證明了錯誤,我通過訪問底層的XML結構創建了Pivot表。 xlsx文件。在這裏我指出數據透視表字段和操作(在這種情況下爲COUNT)。

我現在正在設計自動JUnit測試來驗證這一點,這是我遇到麻煩的地方。

問題: 當生成包含文檔的XLSX,樞軸表僅與後我在客戶端打開它的值填充。

我想問一下是否有方法在我打開客戶端之前以編程方式觸發數據透視表。 這裏是XLSX的文檔的底層XML(pivotTable1.xml)的2個部分:

在Excel客戶端開口之前:

<location firstDataCol="1" firstDataRow="1" firstHeaderRow="1" ref="A3:D7"/> 
<pivotFields count="8"> 
<pivotField showAll="false" axis="axisPage"> 
<items count="8"> 
<item t="default"/> 
<item t="default"/> 
<item t="default"/> 

在Excel客戶端開口後

<pivotFields count="8"> 
<pivotField axis="axisPage" showAll="0"> 
<items count="2"> 
<item x="0"/> 
<item t="default"/> 
</items> 

如果我嘗試在JUnit中使用生成的Excel,在打開它之前,我得到一個NULL: currentWbSheet.getRow(0)。 如果我先打開文件然後運行測試,則不會發生這種情況。

你知道一種生成數據透視表的方式,可以通過這種方式來計算數據透視表的生成或如何從我的Java應用程序中觸發它?

我的目標是將此生成的xlsx與已知(「黃金」)xlsx測試進行比較,並逐個驗證其內容是否相同。

代碼示例: 工作簿表單生成:

private void createSheets(XSSFWorkbook wb) { 
    generalDataSheet = wb.createSheet(GENERAL_DATA_SHEET_NAME); 
    pivotTableSheet = wb.createSheet(PIVOT_TABLE_SHEET_NAME); 
} 

數據透視表的實現和使用的詳細信息:

// Pivot table constants: 
// where the Table starts with the Report Filter field 
public static final String PIVOT_TABLE_SOURCE_START = "A1"; 
// Where the 2nd part of the pivot table starts with the Sum Values field 
public static final String PIVOT_TABLE_DATA_START = "A3:B3"; 
private static final String PIVOT_TABLE_NAME = " Pivot Table"; 

private static final int INTERFACE_NAME_CELL_POS = 0; 
private static final int PROVIDER_NAME_CELL_POS = 4; 
private static final int REQUESTER_NAME_CELL_POS = 6; 

… 
private void populatePivotTableSheet(List<MyDataSet> list) { 
//Set position of the pivot table in sheet 
    CellReference pivotTableCellPosition = new CellReference(PIVOT_TABLE_SOURCE_START); 
    //set source area for the pivot table 
    AreaReference pivotTableSourceArea = getDefaultPivotTableSourceArea(list); 
// create pivot table and set attributespivotTable = new PivotTableMyTools(pivotTableSourceArea, PIVOT_TABLE_NAME); 
    pivotTable.createPivotTable(pivotTableSheet, pivotTableCellPosition); 
    // set the size of the pivot Table - this is because of a bug in regular API 
    pivotTable.setRefField(PIVOT_TABLE_DATA_START); 
    pivotTable.addRowLabelsField(PROVIDER_NAME_CELL_POS); 
    pivotTable.addColumnLabelsField(REQUESTER_NAME_CELL_POS); 
    pivotTable.addReportFilterField(INTERFACE_NAME_CELL_POS); 
pivotTable.addSumValuesField(DataConsolidateFunction.COUNT,PROVIDER_NAME_CELL_POS); 
    } 

我得到的數據透視表像源區:

private AreaReference getDefaultPivotTableSourceArea(Object linkSetList) { 

List<MyDataSet> list = (List<MyDataSet>) DataSetList; 
// construct the target area of the Pivot table 
// start cell is calculated as for ex: "General data!A2" 
CellReference c1 = new CellReference(GENERAL_DATA_SHEET_NAME + "!" + PIVOT_TABLE_SOURCE_START); 
String colName = CellReference.convertNumToColString(COLUMN_HEADERS.length - 1); 
// end cell is calculated as for ex: "General data!H5" 
CellReference c2 = new CellReference(GENERAL_DATA_SHEET_NAME + "!" + colName + (list.size() + 1)); 

return new AreaReference(c1, c2); 
} 

然後我用我自己的數據透視表類覆蓋的一些方法:

public class PivotTableMyTools extends XSSFPivotTable implements IPivotTableMyTools { 

    private XSSFSheet pivotTableSheet; // Sheet displaying information in pivot 
    private AreaReference sourceDataArea; 
    private XSSFPivotTable pivotTable; 
    private int numberOfDataFields; 
    private String pivotTableName; 

public PivotTableMyTools(AreaReference sourceDataArea, String pivotTableName) { 

     this.sourceDataArea = sourceDataArea; 
     numberOfDataFields = 0; 
     this.pivotTableName = pivotTableName; 
    } 

@Override 
public void createPivotTable(XSSFSheet destinationSheet, CellReference pivotTableCellPosition) { 

     pivotTableSheet = destinationSheet; 
     pivotTable = pivotTableSheet.createPivotTable(sourceDataArea, pivotTableCellPosition); 
     pivotTable.getCTPivotTableDefinition().setName(pivotTableName); 
    } 

// int fieldID is the ID of the field in the list of fields to be added to 
// the report (column headers of the source data area) 
@Override 
public void addReportFilterField(int fieldID) { 

    int lastColIndex = getSourceAreaLastColumnIndex(); 
    // create new pivot field with Column Specifications 
    try { 
     // throws index out of bounds 
     checkColumnIndexOutOfBounds(fieldID, lastColIndex); 
     // add pivot field to PivotTable, lastColindex also indicates the 
     // number of columns 
     addNewPivotField(fieldID, lastColIndex, STAxis.AXIS_PAGE); 
     // Columns labels colField should be added. 
     addNewCTPageField(fieldID); 

    } catch (IndexOutOfBoundsException e) { 
     Activator.logInfo("Column index is out of bounds"); 
     Activator.logError(e.getMessage()); 
    } 

} 



private void addNewCTPageField(int columnIndex) { 

     CTPageFields pageFields; 
     if (pivotTable.getCTPivotTableDefinition().getPageFields() != null) { 
      pageFields = pivotTable.getCTPivotTableDefinition().getPageFields(); 
     } else { 
      pageFields = pivotTable.getCTPivotTableDefinition().addNewPageFields(); 
     } 
     // Set the fld and hier attributes 
     CTPageField pageField = pageFields.addNewPageField(); 
     pageField.setFld(columnIndex); 
     pageField.setHier(-1); 
     // set the count attribute 
     pageFields.setCount(pageFields.sizeOfPageFieldArray()); 

    } 



@Override 
    public void addRowLabelsField(int columnIndex) { 

     pivotTable.addRowLabel(columnIndex); 
    } 

    @Override 
    public void addColumnLabelsField(int columnIndex) { 

     int lastColIndex = getSourceAreaLastColumnIndex(); 
     // create new pivot field with Column Specifications 
     try { 
      // throws index out of bounds 
      checkColumnIndexOutOfBounds(columnIndex, lastColIndex); 
      // add pivot field to PivotTable, lastColindex also indicates the 
      // number of columns 
      addNewPivotField(columnIndex, lastColIndex, STAxis.AXIS_COL); 
      // Columns labels colField should be added. 
      addNewCTColField(columnIndex); 

     } catch (IndexOutOfBoundsException e) { 
      Activator.logInfo("Column index is out of bounds"); 
      Activator.logError(e.getMessage()); 
     } 
    } 

    @Override 
    public void addSumValuesField(DataConsolidateFunction function, int fieldID) { 

     // pivotTable.addColumnLabel(DataConsolidateFunction.COUNT, 
     // PROVIDER_NAME_CELL_POS, "Provider count"); 
     try { 
      CTPivotField pivotField = getPivotField(fieldID); 
      pivotField.setDataField(true); 
     } catch (IndexOutOfBoundsException e) { 
      Activator.logInfo("The selected column is out of current range"); 
      Activator.logError(e.getMessage()); 
     } 

     addNewCTDataField(fieldID, "Count of Provider"); 

    } 



private void addNewCTDataField(int fieldID, String fieldName) { 

     numberOfDataFields++; 
     CTDataFields dataFields = pivotTable.getCTPivotTableDefinition().addNewDataFields(); 
     CTDataField dataField = dataFields.addNewDataField(); 
     dataField.setName(fieldName); 
     dataField.setFld(fieldID); 
     dataField.setSubtotal(STDataConsolidateFunction.COUNT); 
     dataField.setBaseField(0); 
     dataField.setBaseItem(0); 
     dataFields.setCount(numberOfDataFields); 
    } 

    private CTPivotField getPivotField(int fieldID) throws IndexOutOfBoundsException { 

     CTPivotFields pivotFields = pivotTable.getCTPivotTableDefinition().getPivotFields(); 
     if (null == pivotFields) 
      throw new IndexOutOfBoundsException(); 
     return pivotFields.getPivotFieldArray(4); 
    } 

    @Override 
    public AreaReference getPivotTableSourceArea() { 

     return sourceDataArea; 
    } 

    @Override 
    public int getSourceAreaLastColumnIndex() { 

     return (sourceDataArea.getLastCell().getCol() - sourceDataArea.getFirstCell().getCol()); 
    } 

    @Override 
    public void setRefField(String pivotTableFieldArea) { 

     CTLocation location = pivotTable.getCTPivotTableDefinition().getLocation(); 
     location.setRef("A3:D7"); 
    } 



/***************** private methods ***********************************/ 

    private void addNewCTColField(int columnIndex) { 

     CTColFields colFields; 
     if (pivotTable.getCTPivotTableDefinition().getColFields() != null) { 
      colFields = pivotTable.getCTPivotTableDefinition().getColFields(); 
     } else { 
      colFields = pivotTable.getCTPivotTableDefinition().addNewColFields(); 
     } 
     colFields.addNewField().setX(columnIndex); 
     colFields.setCount(colFields.sizeOfFieldArray()); 
    } 

    private void addNewPivotField(int columnIndex, int numberOfItems, Enum axisValue) { 

     IPivotFieldARTools pivotField = new PivotFieldARTools(); 
     pivotField.setAxis(axisValue); 
     pivotField.createItemsList(numberOfItems); 
     pivotField.addToPivotTable(columnIndex, pivotTable); 
    } 

    private void checkColumnIndexOutOfBounds(int columnIndex, int lastColIndex) throws IndexOutOfBoundsException { 

     if (columnIndex > lastColIndex && columnIndex < 0) { 
      throw new IndexOutOfBoundsException(); 
     } 
    } 

回答

0

解決方法這個問題,我將創建一個VBScript的應用程序,我可以一起出貨我的插件,可以從插件觸發。

。此應用程序將執行的操作是:在Excel客戶端中打開作爲參數接收的Excel文件,然後保存該文件並關閉客戶端。

。這應該會觸發Excel所執行的數據透視表生成步驟,並允許我使用數據透視表自動生成完整的Excel。

缺點:

。我必須到達外部Java庫來執行此操作。

。我必須執行額外的步驟:打開/保存並關閉Excel客戶端。 爲我的解決辦法的WScript的代碼看起來是這樣的:

excelOpenSave.vbs:

on error resume next 

點心文件名
文件名= WScript.Arguments(0)

「WScript.Echo文件名

Set objExcel = CreateObject("Excel.Application") 
objExcel.DisplayAlerts = False 
Set objWorkbook = objExcel.Workbooks.Open(filename) 
objExcel.Visible = true 
objWorkbook.RefreshAll 


objExcel.ActiveWorkbook.Save 
objExcel.ActiveWorkbook.Close SaveChanges=True 
objExcel.Application.Quit 
'WScript.Echo "Finished." 


'always deallocate after use... 
Set objWorkbook = Nothing 
Set objExcel = Nothing 
WScript.Quit 

我的Java代碼是:

public static void triggerOpenSaveCloseScript(String file) { 

    String projPath = System.getProperty("user.dir"); 
    String script = projPath + "\\Script\\excelOpenSave.vbs"; 
    String command = "CScript " + script + " " + file; 
    int exitValue = 0; 
    try { 
     Runtime rt = Runtime.getRuntime(); 
     Process pr = rt.exec(command); 
     exitValue = pr.waitFor(); //wait until script finishes 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } catch (InterruptedException e) { 
     System.out.println("CScript exited with error: " + exitValue); 
     e.printStackTrace(); 
    } 
}