如何使用Poi设置数据透视表中行标签的默认值

时间:2019-09-26 14:48:36

标签: java excel apache-poi

我正在使用Excel报告。我需要生成带有某些特定字段的数据透视表,作为行标签中的默认值,而不是选择所有字段。我正在使用apache POI。

This what I am getting automatically when I load excel sheet

This is what I need

AreaReference source = new AreaReference("A1:D5", SpreadsheetVersion.EXCEL2007);
        CellReference position = new CellReference(10,0);

         XSSFPivotTable pivotTable = sheet1.createPivotTable(source, position,wb.getSheet("1econtent"));

         pivotTable.addReportFilter(2);
         pivotTable.addRowLabel(0);

         pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 1);
         pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 1,"% of value");

         pivotTable.getCTPivotTableDefinition().getDataFields().getDataFieldArray(1).setShowDataAs(org.openxmlformats.schemas.spreadsheetml.x2006.main.STShowDataAs.PERCENT_OF_COL);
         DataFormat dataformat = wb.createDataFormat();
         short numFmtId = dataformat.getFormat("0.00%");
         pivotTable.getCTPivotTableDefinition().getDataFields().getDataFieldArray(1).setNumFmtId(numFmtId); 
         pivotTable.getCTPivotTableDefinition().getPivotTableStyleInfo().setName("PivotStyleMedium10");

我尝试了很多方法,但没有找到任何答案。

1 个答案:

答案 0 :(得分:0)

apache poi中创建数据透视表直到现在还只是初步的。

Apache poi添加与数据源中的行一样多的类型为“默认”(<item t="default"/>)的数据透视字段项。这是因为他们不想看数据,因此他们假定数据源中的行与行中的行一样多。这很好,因为Excel在打开时将重建其数据透视缓存。

但是如果我们要预选项目,那就不好了。然后,我们必须知道可以预选哪些项目。

因此,我们至少需要与希望预选编号的项目一样多的项目:<item x="0"/><item x="1"/><item x="2"/>...。而且我们必须建立一个缓存定义,其中包含这些项目的共享元素。

要满足该要求,我们需要确定数据源中所有行的唯一标签。然后,对于每个唯一标签,将该项目作为编号项目。然后构建一个缓存定义,其中包含这些项目的共享元素。然后将所有不需要的物品都隐藏起来。

让我们有一个完整的示例,该示例创建您在问题图片中显示的内容。您问题中的代码不完整,因此我必须预测您拥有哪些数据作为数据源。请在其他问题中尽量避免这种情况,并始终提供Minimal, Reproducible Example。否则您将无法获得进一步的答案。

import java.io.FileOutputStream;

import org.apache.poi.ss.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.xssf.usermodel.*;

class CreatePivotTablePercentAndFilter {

 public static void main(String[] args) throws Exception {

  try (Workbook workbook = new XSSFWorkbook(); 
       FileOutputStream fileout = new FileOutputStream("ooxml-pivottable.xlsx") ) {

   Sheet pivotSheet = workbook.createSheet("Pivot");
   Sheet dataSheet = workbook.createSheet("Data");

   setCellData(dataSheet);

   AreaReference areaReference = new AreaReference("A1:D5", SpreadsheetVersion.EXCEL2007);

   XSSFPivotTable pivotTable = ((XSSFSheet)pivotSheet).createPivotTable(areaReference, new CellReference("A4"), dataSheet);

   pivotTable.addRowLabel(0);

   pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 1);
   pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 1,"% of value");

   pivotTable.getCTPivotTableDefinition().getDataFields().getDataFieldArray(1).setShowDataAs(
    org.openxmlformats.schemas.spreadsheetml.x2006.main.STShowDataAs.PERCENT_OF_COL);
   DataFormat dataformat = workbook.createDataFormat();
   short numFmtId = dataformat.getFormat("0.00%");
   pivotTable.getCTPivotTableDefinition().getDataFields().getDataFieldArray(1).setNumFmtId(numFmtId);

   /*   
   Apache poi adds 5 pivot field items of type "default" (<item t="default"/>) for each row label here. 
   This is because there are 5 rows (A1:D5) and, because they don't want have a look at the data, 
   they are assuming max 5 different values. 
   This is fine because Excel will rebuild its pivot cache while opening. 

   But if we want preselect items, then this is not fine. Then we must know what items there are that can be preselected.

   So we need at least as much items as we want preselect being numbered items: <item x="0"/><item x="1"/><item x="2"/>...
   And we must build a cache definition which has shared elements for those items.

   To fulfill that we need determine the unique labels in column. 
   Then for each unique label take the item as numbered item. 
   Then build a cache definition which has shared elements for those items. 
   Then set all not wanted items hidden.
   */

   //determine unique labels in column 0
   java.util.TreeSet<String> uniqueItems = new java.util.TreeSet<String>();
   for (int r = areaReference.getFirstCell().getRow()+1; r < areaReference.getLastCell().getRow()+1; r++) {
    uniqueItems.add(dataSheet.getRow(r).getCell(areaReference.getFirstCell().getCol()).getStringCellValue());
   }
   System.out.println(uniqueItems);
   int i = 0;
   for (String item : uniqueItems) {
    //take the items as numbered items: <item x="0"/><item x="1"/><item x="2"/>
    pivotTable.getCTPivotTableDefinition().getPivotFields().getPivotFieldArray(0).getItems().getItemArray(i).unsetT();
    pivotTable.getCTPivotTableDefinition().getPivotFields().getPivotFieldArray(0).getItems().getItemArray(i).setX((long)i);
    //build a cache definition which has shared elements for those items 
    //<sharedItems><s v="Jack"/><s v="Jane"/><s v="Tarzan"/><s v="Terk"/></sharedItems>
    pivotTable.getPivotCacheDefinition().getCTPivotCacheDefinition().getCacheFields().getCacheFieldArray(0)
    .getSharedItems().addNewS().setV(item);
    i++;
   }

   //Now we can predefinite a filter.
   //If the need is selecting multiple items, first MultipleItemSelectionAllowed needs to be set.
   pivotTable.getCTPivotTableDefinition().getPivotFields().getPivotFieldArray(0).setMultipleItemSelectionAllowed(true);
   //Then set H(idden) true for all items which not shall be selected. All except "Jane" in this case.
   i = 0;
   for (String item : uniqueItems) {
    if (!"Jane".equals(item))
     pivotTable.getCTPivotTableDefinition().getPivotFields().getPivotFieldArray(0).getItems().getItemArray(i).setH(true);
    i++;
   }

   workbook.write(fileout);
  }
 }

 static void setCellData(Sheet sheet) {
  Row row;
  Cell cell;
  Object[][] data = new Object[][]{
   new Object[]{"Names", "Values", "ColC", "ColD"},
   new Object[]{"Jane", 10d, "?", "?"},
   new Object[]{"Tarzan", 5d, "?", "?"},
   new Object[]{"Terk", 10d, "?", "?"},
   new Object[]{"Jack", 10d, "?", "?"}
  };
  for (int r = 0; r < data.length; r++) {
   row = sheet.createRow(r);
   Object[] rowData = data[r];
   for (int c = 0; c < rowData.length; c++) {
    cell = row.createCell(c);
    if (rowData[c] instanceof String) {
     cell.setCellValue((String)rowData[c]);
    } else if (rowData[c] instanceof Double) {
     cell.setCellValue((Double)rowData[c]);
    }
   }
  }
 }
}