Apache POI XSSFPivotTable setDefaultSubtotal

Joh*_*hns 2 java excel pivot-table apache-poi

我遇到了axisRow pivotFields的setDefaultSubtotal方法的问题.当我为RowLabel字段将值设置为false时,Excel不喜欢它.手动设置我在Excel中如何想要它们然后保存会产生截然不同的XML,这与我在幕后进行修复是完全不同的.我不能(到目前为止)操纵XML以使POI电子表格在Excel中干净地打开.

实际的代码有点长而且难以发布,但这里有一个具有相同问题的可运行的代码:

private static void sample() throws IOException{
    Workbook wb = new XSSFWorkbook();
    String[][] data = new String[][]{{"STATUS","PASSED","VALUE"},{"BLUE","Y","20"},{"RED","N","10"},{"BLUE","N","30"}};

    XSSFSheet sheet = (XSSFSheet) wb.createSheet("data");
    XSSFSheet pivot = (XSSFSheet) wb.createSheet("summary");
    for(String[] dataRow : data){
        XSSFRow row = sheet.createRow(sheet.getPhysicalNumberOfRows());
        for(String dataCell : dataRow){
            XSSFCell cell = row.createCell(row.getPhysicalNumberOfCells());
            cell.setCellValue(dataCell);
        }
    }

    XSSFTable table = sheet.createTable();    
    CTTable cttable = table.getCTTable();
    table.setDisplayName("table");
    cttable.setRef("A1:C4");
    cttable.setId(1);

    CTTableColumns columns = cttable.addNewTableColumns();
    columns.setCount(3);

    int i = 1;
    for (String colName : data[0]){
        CTTableColumn column = columns.addNewTableColumn();
        column.setId(++i);
        column.setName(colName);      
    }

    XSSFPivotTable pivotTable =  pivot.createPivotTable(new AreaReference("A1:C4", SpreadsheetVersion.EXCEL2007), new CellReference("A4"), sheet);

    pivotTable.addRowLabel(0);
    CTPivotField fld = pivotTable.getCTPivotTableDefinition().getPivotFields().getPivotFieldList().get(0);
    fld.setOutline(false);

    //fld.setDefaultSubtotal(false); // uncomment and Excel has problems

    pivotTable.addRowLabel(1);
    fld = pivotTable.getCTPivotTableDefinition().getPivotFields().getPivotFieldList().get(1);
    fld.setOutline(false);

    //fld.setDefaultSubtotal(false); // uncomment and Excel has problems

    pivotTable.addColumnLabel(DataConsolidateFunction.COUNT, 2, "test");

    FileOutputStream fileOut = new FileOutputStream("c:/temp/pivotsample.xlsx");
    wb.write(fileOut);
    wb.close();

}
Run Code Online (Sandbox Code Playgroud)

当我生成POI版本时,这些是存档中pivotTable XML的location和pivotFields元素:

<location firstDataCol="1" firstDataRow="1" firstHeaderRow="1" ref="F10:G11" colPageCount="1"/>
<pivotFields count="5">
    <pivotField axis="axisRow" showAll="false" compact="true" outline="false" defaultSubtotal="false">
        <items count="4">
            <item t="default"/>
            <item t="default"/>
            <item t="default"/>
            <item t="default"/>
        </items>
    </pivotField>
    <pivotField dataField="true" showAll="false"/>
    <pivotField dataField="true" showAll="false"/>
    <pivotField axis="axisPage" showAll="false">
        <items count="4">
            <item t="default"/>
            <item t="default"/>
            <item t="default"/>
            <item t="default"/>
        </items>
    </pivotField>
    <pivotField axis="axisRow" showAll="false" compact="true" outline="false" defaultSubtotal="false">
        <items count="4">
            <item t="default"/>
            <item t="default"/>
            <item t="default"/>
            <item t="default"/>
        </items>
    </pivotField>
</pivotFields>
Run Code Online (Sandbox Code Playgroud)

当我在Excel中打开并允许它恢复工作表时,我然后在Excel中进行更改以执行我想要的操作,即以表格形式没有小计的两个行标签,这是Excel保存的内容:

<location ref="F10:I15" firstHeaderRow="1" firstDataRow="2" firstDataCol="2" rowPageCount="1" colPageCount="1"/>
<pivotFields count="5">
    <pivotField axis="axisRow" outline="0" showAll="0" defaultSubtotal="0">
        <items count="3">
            <item x="0"/>
            <item x="1"/>
            <item x="2"/>
        </items>
    </pivotField>
    <pivotField dataField="1" showAll="0"/>
    <pivotField dataField="1" showAll="0"/>
    <pivotField axis="axisPage" showAll="0">
        <items count="3">
            <item x="0"/>
            <item x="1"/>
            <item t="default"/>
        </items>
    </pivotField>
    <pivotField axis="axisRow" outline="0" showAll="0" defaultSubtotal="0">
        <items count="2">
            <item x="0"/>
            <item x="1"/>
        </items>
    </pivotField>
</pivotFields>
Run Code Online (Sandbox Code Playgroud)

我已经尝试了所有的东西,我理解Excel格式,但它依赖于pivotCacheRecords,所以我最终不得不编写代码来填充它.如果有人可以看到为什么这个代码失败了,我会很感激指针.

Axe*_*ter 5

另请参见如何在Apache POI数据透视表报告筛选器中设置默认值.

到目前为止<item t="default"/>,如果数据范围中存在行,则apache poi会添加"default"()类型的数据透视字段项,如果数据库字段用作轴字段.这是因为他们不想查看数据,因此他们假设数据中的行具有尽可能多的不同值.

这很好,因为Excel将在打开时重建其数据透视表缓存.但是,如果我们想要更改默认值,那么这不是很好.然后我们必须知道有什么项目.

因此,我们至少需要与数据中的不同项目一样多的项目作为编号项目: <item x="0"/><item x="1"/>

我们需要构建一个缓存定义,它具有这些项的共享元素.

例:

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

import java.io.*;

import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;

class PivotTableTest6 {

 public static void main(String[] args) throws IOException{
    Workbook wb = new XSSFWorkbook();
    String[][] data = new String[][]{{"STATUS","PASSED","VALUE"},{"BLUE","Y","20"},{"RED","N","10"},{"BLUE","N","30"}};

    XSSFSheet sheet = (XSSFSheet) wb.createSheet("data");
    XSSFSheet pivot = (XSSFSheet) wb.createSheet("summary");
    for(String[] dataRow : data){
        XSSFRow row = sheet.createRow(sheet.getPhysicalNumberOfRows());
        for(String dataCell : dataRow){
            XSSFCell cell = row.createCell(row.getPhysicalNumberOfCells());
            cell.setCellValue(dataCell);
        }
    }

    XSSFTable table = sheet.createTable();    
    CTTable cttable = table.getCTTable();
    table.setDisplayName("table");
    cttable.setRef("A1:C4");
    cttable.setId(1);

    CTTableColumns columns = cttable.addNewTableColumns();
    columns.setCount(3);

    int i = 1;
    for (String colName : data[0]){
        CTTableColumn column = columns.addNewTableColumn();
        column.setId(++i);
        column.setName(colName);      
    }

    XSSFPivotTable pivotTable =  pivot.createPivotTable(new AreaReference("A1:C4", SpreadsheetVersion.EXCEL2007), new CellReference("A4"), sheet);

    pivotTable.addRowLabel(0);
    CTPivotField fld = pivotTable.getCTPivotTableDefinition().getPivotFields().getPivotFieldList().get(0);
    fld.setOutline(false);

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

    But if we want changing defaults, then this is not fine. Then we must know what items there are.

    So we need at least as much items, as are different ones in the data, as numbered items: <item x="0"/><item x="1"/> 

    And we must build a cache definition which has shared elements for those items.
    */

    for (i = 0; i < 2; i++) {
     //take the first 2 items as numbered items: <item x="0"/><item x="1"/>
     fld.getItems().getItemArray(i).unsetT();
     fld.getItems().getItemArray(i).setX((long)i);
    }
    for (i = 3; i > 1; i--) {
     //remove further items
     fld.getItems().removeItem(i);
    }
    //set new items count
    fld.getItems().setCount(2);

    //build a cache definition which has shared elements for those items 
    //<sharedItems><s v="Y"/><s v="N"/></sharedItems>
    pivotTable.getPivotCacheDefinition().getCTPivotCacheDefinition().getCacheFields().getCacheFieldList().get(0).getSharedItems().addNewS().setV("Y");
    pivotTable.getPivotCacheDefinition().getCTPivotCacheDefinition().getCacheFields().getCacheFieldList().get(0).getSharedItems().addNewS().setV("N");

    fld.setDefaultSubtotal(false);

    pivotTable.addRowLabel(1);
    fld = pivotTable.getCTPivotTableDefinition().getPivotFields().getPivotFieldList().get(1);
    fld.setOutline(false);

    pivotTable.addColumnLabel(DataConsolidateFunction.COUNT, 2, "test");

    FileOutputStream fileOut = new FileOutputStream("pivotsample6.xlsx");
    wb.write(fileOut);
    wb.close();

 }
}
Run Code Online (Sandbox Code Playgroud)