Apache POI: как установить фильтр THIS_YEAR в дате метки строки сводной таблицы

#java #excel #apache-poi

#java #excel #apache-poi

Вопрос:

Я пытаюсь создать сводную таблицу в Excel с помощью apache poi. Мое требование — применить фильтр даты (В ЭТОМ ГОДУ), т.е. Отображать только даты текущего года в метке строки даты в сводке.

Проблема: ниже воспроизводимый код, который генерирует выходной файл Excel с фильтром «THIS_YEAR», примененным к столбцу даты, но по какой-то причине он не показывает никаких данных.

Ниже приведен код для генерации выходных данных.

 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.*;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;

import java.util.GregorianCalendar;

class CreatePivotTableFilter {

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

  try (Workbook workbook = new XSSFWorkbook(); 
       FileOutputStream fileout = new FileOutputStream("Excel.xlsx") ) {

   DataFormat format = workbook.createDataFormat();
   CellStyle dateStyle = workbook.createCellStyle();
   dateStyle.setDataFormat(format.getFormat("M\/d\/yy"));

   Sheet sheet = workbook.createSheet();

   String[] headers = new String[]{"Column1", "Column2", "Date", "Count"};
   Row row = sheet.createRow(0);
   Cell cell;
   for (int c = 0; c < headers.length; c  ) {
    cell = row.createCell(c); cell.setCellValue(headers[c]);
   }

   Object[][] data = new Object[][]{
    new Object[]{"A", "B1", new GregorianCalendar(2020, 0, 2), 2d},
    new Object[]{"A", "B2", new GregorianCalendar(2020, 0, 1), 4d},
    new Object[]{"B", "B1", new GregorianCalendar(2019, 0, 2), 1d},
    new Object[]{"B", "B2", new GregorianCalendar(2019, 0, 2), 7d},
    new Object[]{"A", "C1", new GregorianCalendar(2019, 0, 1), 5d},
    new Object[]{"A", "C2", new GregorianCalendar(2019, 0, 1), 5d},
    new Object[]{"B", "C1", new GregorianCalendar(2019, 0, 2), 2d},
    new Object[]{"B", "C2", new GregorianCalendar(2019, 0, 2), 8d}
   };
   for (int r = 0; r < data.length; r  ) {
    row = sheet.createRow(r 1);
    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 GregorianCalendar) {
      cell.setCellValue((GregorianCalendar)rowData[c]);
      cell.setCellStyle(dateStyle);
     } else if (rowData[c] instanceof Double) {
      cell.setCellValue((Double)rowData[c]);
     }
    }
   }

   XSSFPivotTable pivotTable = ((XSSFSheet)sheet).createPivotTable(
    new AreaReference("A1:D9", 
    SpreadsheetVersion.EXCEL2007), 
    new CellReference("F4"));

   pivotTable.addRowLabel(0);
   pivotTable.addRowLabel(1);
   pivotTable.addRowLabel(2);
 
   pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 3);
   pivotTable.addColumnLabel(DataConsolidateFunction.AVERAGE, 3);

   CTPivotFilters filters = CTPivotFilters.Factory.newInstance();
   CTPivotFilter filter = filters.addNewFilter();
   filter.setId(0);
   filter.setFld(2);
   filter.setType(STPivotFilterType.THIS_YEAR);
   CTFilterColumn filterColumn = filter.addNewAutoFilter().addNewFilterColumn();
   filterColumn.setColId(0);
   CTFilters ctFilters = filterColumn.addNewFilters();
   ctFilter.addNewFilter().setVal("This Year Filter");
    
   //set filters to pivot table definition
   pivotTable.getCTPivotTableDefinition().setFilters(filters);

   workbook.write(fileout);

  }

 }
}
  

Вывод, сгенерированный кодом

введите описание изображения здесь

введите описание изображения здесь

Ожидаемый результат

введите описание изображения здесь

Ответ №1:

Лучший способ работы с низкоуровневыми ooxml-schemas классами — создать все, что нужно, используя Excel ‘s GUI , затем разархивировать полученный *.xlsx файл и посмотреть XML , что GUI он создал.

В этом случае в xl/pivotTables/pivotTable1.xml мы находим:

 ...
<filters>
 <filter fld="2" type="thisYear" id="0">
  <autoFilter>
   <filterColumn colId="0">
    <dynamicFilter type="thisYear"/>
   </filterColumn>
  </autoFilter>
 </filter>
</filters>
...
  

So filterColumn не содержит <filters><filter ...> , но содержит dynamicFilter of type thisYear .

Таким образом, ваш код должен быть:

 ...
   CTPivotFilters filters = CTPivotFilters.Factory.newInstance();
   CTPivotFilter filter = filters.addNewFilter();
   filter.setId(0);
   filter.setFld(2);
   filter.setType(STPivotFilterType.THIS_YEAR);
   CTFilterColumn filterColumn = filter.addNewAutoFilter().addNewFilterColumn();
   filterColumn.setColId(0);
   CTDynamicFilter ctDynamicFilter = filterColumn.addNewDynamicFilter();
   ctDynamicFilter.setType(STDynamicFilterType.THIS_YEAR);
    
   //set filters to pivot table definition
   pivotTable.getCTPivotTableDefinition().setFilters(filters);
...
  

К сожалению API ooxml-schemas , общедоступной документации нет. Поэтому, если нам это нужно, нам нужно загрузить ooxml-schemas исходные maven тексты. Затем мы можем создать API документацию, используя javadoc . Там мы можем найти поля и методы CTFilterColumn , например.

Комментарии:

1. Спасибо за то, что вы так быстро и активно отвечаете на вопросы apache poi. Ваши ответы в сообществе очень помогли мне в создании очень продвинутых сводных данных Excel.