XSSF(POI) – 更改数据透视表上的字体

我正在使用Apache POI 3.12:

<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.12</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.12</version> </dependency> 

如何更改数据透视表中的字体? 将单元格(I7)的字体更改为大小8pt后,检查生成的.xlsx会显示以下更改:

styles.xml中,在标签内作为第二项:

 <font> <sz val="8"/> <color indexed="8"/> <name val="Calibri"/> <family val="2"/> <scheme val="minor"/> </font> within the <cellXfs> tag as the 5th entry: <xf numFmtId="0" fontId="1" fillId="0" borderId="0" xfId="0" applyNumberFormat="1" applyFont="1"/> New tag: dxfs: <dxfs count="1"> <dxf> <font> <sz val="8"/> </font> </dxf> </dxfs> 

pivottable.xml

 <formats count="1"> <format dxfId="0"> <pivotArea collapsedLevelsAreSubtotals="1" fieldPosition="0"> <references count="2"> <reference field="4294967294" count="1" selected="0"> <xv="0"/> </reference> <reference field="0" count="1"> <xv="0"/> </reference> </references> </pivotArea> </format> </formats> 

sheet1.xml

 <cr="I7" s="4"> 

注意:我可能会将此作为自我回答,因为我仍然试图自己解决这个问题。 不过,我已经在这个近一个星期了。 POI数据透视表示例

这是一个部分的答案,因为它需要使用excel来设置,而不是纯粹的poi。

一般步骤:

  1. 在Excel中使用数据透视表创build电子表格,或者使用poi的示例 。
  2. 在Excel中打开电子表格并保存
  3. 在poi中打开电子表格。
  4. 创build一个CTDxfs条目。 这是表格的“字体”。
  5. 使用CTDXfs标识创build一个pivotArea定义。

在代码上:

 private static CTFormats getFormats(XSSFPivotTable pivotTable) { CTFormats formats = pivotTable.getCTPivotTableDefinition().getFormats(); if(formats==null) formats=pivotTable.getCTPivotTableDefinition().addNewFormats(); return formats; } private static int createDXFs(XSSFWorkbook wb,int font) { CTDxfs dxfs=wb.getStylesSource().getCTStylesheet().getDxfs(); if(dxfs==null) dxfs=wb.getStylesSource().getCTStylesheet().addNewDxfs(); dxfs.setCount(dxfs.getCount()+1); CTDxf dxf=dxfs.addNewDxf(); CTFontSize fontSize=dxf.addNewFont().addNewSz(); fontSize.setVal(font); return (int) dxfs.getCount()-1; } public static void setAxisFont(CTFormats pivotTableFormats,int dxfId) { CTFormat format=pivotTableFormats.addNewFormat(); format.setDxfId(dxfId); CTPivotArea pivotArea = format.addNewPivotArea(); pivotArea.setDataOnly(false); pivotArea.setLabelOnly(true); pivotArea.setOutline(false); pivotArea.setFieldPosition(0L); pivotArea.setAxis(STAxis.AXIS_ROW); pivotArea.setType(STPivotAreaType.BUTTON); } public static void setColHeaderFont(CTFormats pivotTableFormats,int dxfId,int colInd) { CTFormat format=pivotTableFormats.addNewFormat(); format.setDxfId(dxfId); CTPivotArea pivotArea = format.addNewPivotArea(); pivotArea.setDataOnly(false); pivotArea.setLabelOnly(true); pivotArea.setOutline(false); CTPivotAreaReferences references = pivotArea.addNewReferences(); CTPivotAreaReference reference = references.addNewReference(); reference.setField(new Long(Integer.MAX_VALUE)*2); CTIndex x = reference.addNewX(); x.setV(colInd); //Column } public static void setLabelFont(CTFormats pivotTableFormats,int dxfId, int rowInd) { CTFormat format=pivotTableFormats.addNewFormat(); format.setDxfId(dxfId); CTPivotArea pivotArea = format.addNewPivotArea(); pivotArea.setDataOnly(false); pivotArea.setLabelOnly(true); pivotArea.setFieldPosition(0L); CTPivotAreaReferences references = pivotArea.addNewReferences(); CTPivotAreaReference reference = references.addNewReference(); reference.setField(0L); CTIndex x = reference.addNewX(); x.setV(rowInd); //Row } public static void setDataElementFont(CTFormats pivotTableFormats,int dxfId,int col,int row) { CTFormat format=pivotTableFormats.addNewFormat(); format.setDxfId(dxfId); CTPivotArea pivotArea = format.addNewPivotArea(); //Default values, don't need to explicitly define. //pivotArea.setDataOnly(true); //pivotArea.setLabelOnly(false); CTPivotAreaReferences references = pivotArea.addNewReferences(); CTPivotAreaReference reference = references.addNewReference(); reference.setField(new Long(Integer.MAX_VALUE)*2); CTIndex x = reference.addNewX(); x.setV(col); //Column reference = references.addNewReference(); reference.setField(0L); x = reference.addNewX(); x.setV(row); //Row } 

笔记:

  • setOutline(false)是需要访问列标题。
  • setDataOnly(false)允许更改影响标签以及数据。
  • setLabelOnly(true)仅将更改限制为标签值。 如果要更改整个列/行,请将其设置为false。
  • unsigned int max值的引用字段值将引用定义为列,另一个有效值为0,将引用定义为一行。
  • 如果col / row引用未定义,如setColHeaderFont / setLabel字体,则会影响整个列/行。 这可能是格式化特定列所需要的。

警告 poi 3.12使用的poi-ooxml-schemas不包含CTFormats。 这可以通过排除它并包括1.1版本来重写:

 <dependency> <groupId>org.apache.poi</groupId> <artifactId>ooxml-schemas</artifactId> <version>1.1</version> </dependency> 

这是一个完整的答案,但比之前使用excel的答案要复杂得多。

一般步骤:

  1. 在Excel中使用数据透视表创build电子表格,或者使用poi的示例 。
  2. 创build一个透视caching定义。
  3. 创build一个CTDxfs条目。 这是表格的“字体”。 (请参阅其他答案)
  4. 使用CTDXfs标识创build一个pivotArea定义。 (请参阅其他答案)

第2步本身看起来是无害的,但却是整个过程的关键。 当Excel打开.xlsx文档时,它将重新validation所有的pivotTable条目,删除任何不再存在的条目,包括CTDXfs条目。 然后它生成caching,然后它应用任何格式。 但是,如果caching不存在,所有格式化规则都会在validation过程中被删除!

下面是我用来生成pivotCache的代码块。 这比正常的stackoverflow的答案,但不知道这是首选或“一般指导”如何做到这一点。

如果需要维护或扩展,请将.xlsx重命名为.zip,将其解压缩,然后在将其保存到Excel中之前和之后查看xl \ pivotTables \ pivotTable1.xml,xl \ pivotCache \ pivotCacheDefinition1.xml。 如果这个工作正常,那么pivotCacheDefinition在保存到excel中后应该大致保持不变。

 public class PivotUtilitiesExample { public static void updateCache(XSSFPivotTable pivotTable) { updateCache(pivotTable,STAxis.AXIS_ROW); updateCache(pivotTable,STAxis.AXIS_COL); updateCache(pivotTable,STAxis.AXIS_PAGE); } /** * Updates the pivotCacheDefinition.xml file. This must be run before any formatting is done. * However, it must also be run *AFTER* the pivotTable's source data is created and all label definitions are defined. * the labels are sorted by default. * @param pivotTable * @param rowLabel if true, updates rowLabels, if false, updates columnLabels. */ private static void updateCache(XSSFPivotTable pivotTable,STAxis.Enum axisType) { XSSFSheet sheet=(XSSFSheet) pivotTable.getDataSheet(); AreaReference pivotArea = new AreaReference(pivotTable.getPivotCacheDefinition(). getCTPivotCacheDefinition().getCacheSource().getWorksheetSource().getRef()); CellReference firstCell = pivotArea.getFirstCell(); CellReference lastCell = pivotArea.getLastCell(); List<Integer> labelColumns=getLabelColumns(pivotTable,axisType); for(int labelCtr=0;labelCtr<labelColumns.size();++labelCtr) { CTSharedItems sharedItems=getSharedItems(pivotTable,labelColumns.get(labelCtr)); //The pivotField entry associated will be the nth axis="axisRow" entry where N is the row label #. CTPivotField pivotField=getPivotField(pivotTable,axisType,labelCtr); CTItems items=pivotField.getItems(); ArrayList<String> toCache=new ArrayList<String>(lastCell.getRow()-firstCell.getRow()); //To make this work, sharedItems and pivotFields must be properly populated. //sharedItems should look like: //<cacheField name="Names" numFmtId="0"> (Cell A1) //<sharedItems count="3"> (Count of unique rows) //<sv="Jane"/> (Cell B1) //<sv="Tarzan"/> (Cell C1) //<sv="Terk"/> (Cell D1) //</sharedItems> //pivotFields should have an entry like this: //<pivotField axis="axisRow" showAll="0"> //<items count="4"> //<item x="0"/> //<item x="1"/> //<item x="2"/> //<item t="default"/> //</items> //Initially, POI will populate with: //<pivotField axis="axisRow" showAll="0"> //<items count="4"> //<item t="default"/> //<item t="default"/> //<item t="default"/> //<item t="default"/> //</items> //Start with firstCell.getRow()+1 since the first row is the column name. for(int i=firstCell.getRow()+1;i<=lastCell.getRow();++i) { String s=sheet.getRow(i).getCell(firstCell.getCol()+labelColumns.get(labelCtr)).getStringCellValue(); //Only add unique entries. if(!toCache.contains(s)) toCache.add(s); } //Blank entries cannot be sorted unless they are specially entered after an M tag. // For most projects this'll be overkill. boolean containsBlank=false; if(toCache.contains("")) { toCache.remove(""); containsBlank=true; } //Remove the old cache list. for(int i=items.sizeOfItemArray()-1;i>=0;--i) items.removeItem(i); for(int i=sharedItems.sizeOfBArray()-1;i>=0;--i) sharedItems.removeB(i); for(int i=sharedItems.sizeOfDArray()-1;i>=0;--i) sharedItems.removeD(i); for(int i=sharedItems.sizeOfEArray()-1;i>=0;--i) sharedItems.removeE(i); for(int i=sharedItems.sizeOfMArray()-1;i>=0;--i) sharedItems.removeM(i); for(int i=sharedItems.sizeOfNArray()-1;i>=0;--i) sharedItems.removeN(i); for(int i=sharedItems.sizeOfSArray()-1;i>=0;--i) sharedItems.removeS(i); sharedItems.setCount(sharedItems.getDomNode().getChildNodes().getLength()); items.setCount(items.sizeOfItemArray()); for(int i=0;i<toCache.size();++i) { CTString string; CTItem item; string=sharedItems.addNewS(); sharedItems.setCount(sharedItems.getDomNode().getChildNodes().getLength()); string.setV(toCache.get(i)); item=items.addNewItem(); items.setCount(items.sizeOfItemArray()); item.setX(i); } //Create the special blank tag. if(containsBlank) { int mPosition; sharedItems.addNewM(); mPosition=sharedItems.sizeOfSArray(); CTString s=sharedItems.addNewS(); s.setV(""); s.setU(true); sharedItems.setCount(sharedItems.getDomNode().getChildNodes().getLength()); sharedItems.setContainsBlank(true); CTItem item=items.addNewItem(); item.setM(true); item.setX(sharedItems.sizeOfSArray()); item=items.addNewItem(); item.setX(mPosition); items.setCount(items.sizeOfItemArray()); } //Add the t="default" entry, required for subtotals. if(!pivotField.isSetDefaultSubtotal() || pivotField.getDefaultSubtotal()==true) { CTItem item; item=items.addNewItem(); items.setCount(items.sizeOfItemArray()); item.setT(STItemType.DEFAULT); } } } //Returns the label columns for all AXIS. Default POI only has a method for RowLabelColumns. private static List<Integer> getLabelColumns(XSSFPivotTable pivotTable,STAxis.Enum axisType) { List<Integer> labelColumns; if(axisType.equals(STAxis.AXIS_ROW)) labelColumns=pivotTable.getRowLabelColumns(); else if(axisType.equals(STAxis.AXIS_COL)) { List<CTField> fieldList = pivotTable.getCTPivotTableDefinition().getColFields().getFieldList(); labelColumns=new ArrayList(fieldList.size()); for(CTField field:fieldList) labelColumns.add(field.getX()); } else if(axisType.equals(STAxis.AXIS_PAGE)) { List<CTPageField> fieldList = pivotTable.getCTPivotTableDefinition().getPageFields().getPageFieldList(); labelColumns=new ArrayList(fieldList.size()); for(CTPageField field:fieldList) labelColumns.add(field.getFld()); } else { throw new UnsupportedOperationException("Error, STAxis: "+axisType+" is not supported"); } return labelColumns; } //Returns the sharedItems entry associated with a particular labelColumn. private static CTSharedItems getSharedItems(XSSFPivotTable pivotTable,int columnIndex) { XSSFSheet sheet=(XSSFSheet) pivotTable.getDataSheet(); AreaReference pivotArea = new AreaReference(pivotTable.getPivotCacheDefinition(). getCTPivotCacheDefinition().getCacheSource().getWorksheetSource().getRef()); CellReference firstCell = pivotArea.getFirstCell(); String labelName=sheet.getRow(firstCell.getRow()).getCell(firstCell.getCol()+columnIndex).getStringCellValue(); List<CTCacheField> cacheFieldList = pivotTable.getPivotCacheDefinition().getCTPivotCacheDefinition().getCacheFields().getCacheFieldList(); CTSharedItems sharedItems=null; //The sharedItem entry associated will have name=labelColumn's name. for(int i=0;i<cacheFieldList.size();++i) if(labelName.equals(cacheFieldList.get(i).getName())) { sharedItems=cacheFieldList.get(i).getSharedItems(); break; } //Should never be true. if(sharedItems==null) { throw new RuntimeException("Error, unable to find sharedItems entry in pivotCacheDefinition.xml"); } return sharedItems; } //Return the nth pivotField entry from the pivotTable definition of a particular Axis. private static CTPivotField getPivotField(XSSFPivotTable pivotTable,STAxis.Enum axisType,int index) { CTPivotFields pivotFields = pivotTable.getCTPivotTableDefinition().getPivotFields(); CTPivotField pivotField=null; for(int i=0,axisRowNum=-1;i<pivotFields.getPivotFieldList().size();++i) { if(axisType.equals(pivotFields.getPivotFieldList().get(i).getAxis())) ++axisRowNum; if(axisRowNum==index) { pivotField=pivotFields.getPivotFieldList().get(i); break; } } if(pivotField==null) throw new RuntimeException("Error, unable to find pivotField entry in pivotTable.xml"); return pivotField; } }