2016-04-15 61 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(); 
    } 
}