Apache POI:默认 Excel 单元格样式

Apache POI: default Excel cell styles

有没有办法在 Apache POI 中使用默认的 Excel 单元格样式(见下文),类似于 BuiltinFormats 中的默认数据格式?

如果“一种使用默认 Excel 单元格样式的方法”意味着能够使用 apache poi 使用命名单元格样式来设置单元格样式,那么不,这是不可能的。

单元格样式模板就是这个,单元格样式模板。如果在 Excel GUI 中选择,GUI 会根据所选模板在工作簿级别创建单元格样式,然后将该单元格样式应用于单元格。不可能仅将单元格样式的名称存储到 Excel 文件中,然后期望 Excel 相应地设置单元格样式。 Apache poi 也必须这样做。但是它必须知道单个模板定义的是什么。但这似乎没有记录在任何地方。 CellStyle Class 状态:

Annex H contains a listing of cellStyles whose corresponding formatting records are implied rather than explicitly saved in the file. In this case, a builtinId attribute is written on the cellStyle record, but no corresponding formatting records are written.

但是我在任何地方都找不到附件 H。可能是我太笨没找到。

我们唯一能做的就是创建自己的自定义命名单元格样式,然后就可以使用了。

而且,如果我们以某种方式获得内置单元格样式模板的 builtinId,那么我们就可以创建单元格样式来覆盖那些内置单元格样式模板。但是 trial/error 只能通过 trial/error 获取内置单元格样式模板的 builtinId,因为它们没有记录:

创建一个 Excel 文件,该文件使用一些内置的单元格样式模板。将该文件另存为 *.xlsx 文件。然后解压缩 *.xlsx 文件并查看 /xl/styles.xml。看看他们有什么builtinId

<cellStyles count="4">
 <cellStyle name="Gut" xfId="1" builtinId="26"/>
 <cellStyle name="Neutral" xfId="3" builtinId="28"/>
 <cellStyle name="Schlecht" xfId="2" builtinId="27"/>
 <cellStyle name="Standard" xfId="0" builtinId="0"/>
</cellStyles>

下面的完整示例同时执行了这两项操作。它创建三个命名的自定义单元格样式,然后在单元格样式模板列表中可见。

它还会覆盖具有 builtinId="26" 的命名单元格样式。这是名为“Good”的单元格样式。

import java.io.FileOutputStream;
import java.io.FileInputStream;

import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.model.StylesTable;

import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXf;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTStylesheet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellStyles;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellStyle;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellStyleXfs;

public class CreateExcelNamedXSSFCellStyle {

 static void setNamedCellStyle(XSSFWorkbook workbook, XSSFCellStyle style, String name, long builtinId) throws Exception {
  
  StylesTable stylestable = workbook.getStylesSource();
  CTStylesheet ctstylesheet = stylestable.getCTStylesheet();

  CTCellStyles ctcellstyles = ctstylesheet.getCellStyles();

  CTXf ctxfcore = style.getCoreXf();

  if (ctcellstyles == null) {
   ctcellstyles = ctstylesheet.addNewCellStyles();
   ctcellstyles.setCount(2);

   CTCellStyle ctcellstyle = ctcellstyles.addNewCellStyle(); //CellStyle for default built-in cell style
   ctcellstyle.setXfId(0);
   ctcellstyle.setBuiltinId(0);

   ctcellstyle = ctcellstyles.addNewCellStyle();
   ctcellstyle.setXfId(1);
   ctcellstyle.setName(name);

   ctxfcore.setXfId(1);
  } else {
   long stylescount = ctcellstyles.getCount();
   ctcellstyles.setCount(stylescount+1);

   CTCellStyle ctcellstyle = ctcellstyles.addNewCellStyle();
   ctcellstyle.setXfId(stylescount);
   ctcellstyle.setName(name);
   if (builtinId > -1) ctcellstyle.setBuiltinId(builtinId);

   ctxfcore.setXfId(stylescount);
  }

  CTXf ctxfstyle = CTXf.Factory.newInstance();  
  ctxfstyle.setNumFmtId(ctxfcore.getNumFmtId());
  ctxfstyle.setFontId(ctxfcore.getFontId());
  ctxfstyle.setFillId(ctxfcore.getFillId());
  ctxfstyle.setBorderId(ctxfcore.getBorderId());

  stylestable.putCellStyleXf(ctxfstyle);

 }

 static XSSFCellStyle getNamedCellStyle(XSSFWorkbook workbook, String name) {
  StylesTable stylestable = workbook.getStylesSource();
  CTStylesheet ctstylesheet = stylestable.getCTStylesheet();
  CTCellStyles ctcellstyles = ctstylesheet.getCellStyles();
  if (ctcellstyles != null) {
   int i = 0;
   XSSFCellStyle style = null;
   while((style = stylestable.getStyleAt(i++)) != null) {
    CTXf ctxfcore = style.getCoreXf();
    long xfid = ctxfcore.getXfId();
    for (CTCellStyle ctcellstyle : ctcellstyles.getCellStyleList()) {
     if (ctcellstyle.getXfId() == xfid && name.equals(ctcellstyle.getName())) {
      return style;
     }
    }
   }
  }
  return workbook.getCellStyleAt(0); //if nothing found return default cell style 
 }

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

  XSSFWorkbook workbook = new XSSFWorkbook();

  //The following creates three named custom cell styles
  IndexedColorMap colorMap = workbook.getStylesSource().getIndexedColors();
  XSSFCellStyle style = workbook.createCellStyle();
  style.setFillForegroundColor(new XSSFColor(new byte[]{(byte)255, 0, 0}, colorMap));
  style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
  setNamedCellStyle(workbook, style, "My Custom Style 1", -1);

  style = workbook.createCellStyle();
  style.setFillForegroundColor(new XSSFColor(new byte[]{0, (byte)255, 0}, colorMap));
  style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
  setNamedCellStyle(workbook, style, "My Custom Style 2", -1);

  style = workbook.createCellStyle();
  style.setFillForegroundColor(new XSSFColor(new byte[]{0, 0, (byte)255}, colorMap));
  style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
  setNamedCellStyle(workbook, style, "My Custom Style 3", -1);

  //The following uses the custom named cell styles
  XSSFSheet sheet = workbook.createSheet("TestSheet");
  XSSFRow row = sheet.createRow(0);
  for (int i = 0; i < 3; i++) {
   XSSFCell cell = row.createCell(i);
   style = getNamedCellStyle(workbook, "My Custom Style " + (i+1));
   cell.setCellStyle(style);
  }

  row = sheet.createRow(2);
  XSSFCell cell = row.createCell(0);
  style = getNamedCellStyle(workbook, "not found");
  cell.setCellStyle(style);
  
  //The following overwrites the named cell style having builtinId="26". This is the cell style named "Good".
  style = workbook.createCellStyle();
  style.setFillForegroundColor(new XSSFColor(new byte[]{(byte)198, (byte)239, (byte)206}, colorMap));
  style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
  setNamedCellStyle(workbook, style, "Good", 26);
  cell = row.createCell(1);
  style = getNamedCellStyle(workbook, "Good");
  cell.setCellStyle(style);

  FileOutputStream out = new FileOutputStream("CreateExcelNamedXSSFCellStyle.xlsx");
  workbook.write(out);
  out.close();
  workbook.close();

 }
}