2014-08-29 193 views
7

我想写ResultSet转Excel(* .xlsx)表使用Apache Poi。在Office ExcelResultSet转Excel(* .xlsx)表使用Apache POI

无效的表对象错误

然而,即使它写入Excel文件没有任何错误,当我尝试在Office Excel 2013中打开它,它显示了一个错误,并删除表格对象只给出纯数据视图。

Message while opening file

Message after removing errors

这里是粗略的示例代码using this example

public static void writeExcel(ResultSet rs, int sqliteRowCount, String dir) { 
    System.out.println("Writing Excel(*.xlsx) File..."); 
    XSSFWorkbook workbook = null; 
    try { 
     if (rs != null) { 
      // Get ResultSet MetaData 
      ResultSetMetaData rsmd = rs.getMetaData(); 
      // Number of columns 
      int numColumns = rsmd.getColumnCount(); 
      // Number of rows 
      // + 1 for headers 
      int numRows = sqliteRowCount + 1; 
      workbook = new XSSFWorkbook(); 

      // Create Excel Table 
      XSSFSheet sheet = workbook.createSheet("Text"); 
      XSSFTable table = sheet.createTable(); 
      table.setDisplayName("Test"); 
      CTTable cttable; 
      cttable = table.getCTTable(); 

      // Style configurations 
      CTTableStyleInfo style = cttable.addNewTableStyleInfo(); 
      style.setName("TableStyleMedium16"); 
      style.setShowColumnStripes(false); 
      style.setShowRowStripes(true); 

      // Set Table Span Area 
      AreaReference reference = new AreaReference(new CellReference(0, 0), new CellReference(numRows - 1, numColumns - 1)); 
      cttable.setRef(reference.formatAsString()); 
      cttable.setId(1); 
      cttable.setName("Test"); 
      cttable.setDisplayName("Test"); 
      cttable.setTotalsRowCount(numRows); 
      cttable.setTotalsRowShown(false); 

      // Create Columns 
      CTTableColumns columns = cttable.addNewTableColumns(); 
      columns.setCount(numColumns); 

      // Create Column, Row, Cell Objects 
      CTTableColumn column; 
      XSSFRow row; 

      // Add Header and Columns 
      XSSFRow headerRow = sheet.createRow(0); 
      for (int i = 0; i < numColumns; i++) { 
       column = columns.addNewTableColumn(); 
       column.setName("Column" + (i + 1)); 
       column.setId(i + 1); 
       headerRow.createCell(i).setCellValue(rsmd.getColumnLabel(i + 1)); 
      } 

      // Write each row from ResultSet 
      int rowNumber = 1; 
      while (rs.next()) { 
       row = sheet.createRow(rowNumber); 
       for (int y = 0; y < numColumns; y++) { 
        row.createCell(y).setCellValue(rs.getString(y + 1)); 
       } 
       rowNumber++; 
      } 

      // Set AutoFilter 
      CTAutoFilter fltr = CTAutoFilter.Factory.newInstance(); 
      fltr.setRef((new AreaReference(new CellReference(0, 0), new CellReference(numRows - 1, numColumns - 1))).formatAsString()); 
      cttable.setAutoFilter(fltr); 
      // sheet.setAutoFilter(CellRangeAddress.valueOf((new AreaReference(new CellReference(0, 0), new CellReference(numRows - 1, numColumns - 1))).formatAsString())); 
      // Freeze Pan 
      sheet.createFreezePane(0, 1, 0, 2); 
     } 
    } catch (SQLException ex) { 
     System.out.println("SQL Error while writing Excel file!"); 
    } finally { 
     try { 
     // Let's write the excel file now 
      if (workbook != null) { 
       String excelDir = dir + File.separator + "workbook.xlsx"; 
       try (final FileOutputStream out = new FileOutputStream(excelDir)) { 
        workbook.write(out); 
       } 
      } 
     } catch (IOException ex) { 
      System.out.println("IO Error while writing Excel summary file!"); 
     } 
    } 
} 

我知道什么是错我的代码,但不能弄明白。 任何想法,为什么会发生这种情况,哪里会出现我的代码中的潜在错误。

更新1:在Excel档案,如果表手动

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<table xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" id="1" name="Table1" displayName="Table1" ref="A1:B881" totalsRowShown="0"><autoFilter ref="A1:B881"/><tableColumns count="2"><tableColumn id="1" name="ID"/><tableColumn id="2" name="Name"/></tableColumns><tableStyleInfo name="TableStyleLight9" showFirstColumn="0" showLastColumn="0" showRowStripes="1" showColumnStripes="0"/></table> 

创建另外使用Apache POI

<?xml version="1.0" encoding="UTF-8"?> 
<table displayName="Test" ref="A1:B881" id="1" name="Test" totalsRowCount="881" xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" totalsRowShown="0"><autoFilter ref="A1:B881"/><tableColumns count="2"><tableColumn name="ID" id="1"/><tableColumn name="Name" id="2"/><tableStyleInfo name="TableStyleMedium2" showColumnStripes="true" showRowStripes="true"/></table> 

表XML文件在Excel档案,如果创建

表XML文件,如果我打开Excel归档文件,它没有由Apache POI创建的主题文件夹,但它存在于一个创建中在Office Excel中手动。奇怪。

更新2: 样品可执行代码(使用NetBeans):

/* 
* To change this license header, choose License Headers in Project Properties. 
* To change this template file, choose Tools | Templates 
* and open the template in the editor. 
*/ 

package apachepoi_exceltest; 

    import java.io.File; 
    import java.io.FileOutputStream; 
    import java.io.IOException; 
    import java.util.HashMap; 
    import java.util.Map; 
    import org.apache.poi.ss.util.AreaReference; 
    import org.apache.poi.ss.util.CellRangeAddress; 
    import org.apache.poi.ss.util.CellReference; 
    import org.apache.poi.xssf.usermodel.XSSFRow; 
    import org.apache.poi.xssf.usermodel.XSSFSheet; 
    import org.apache.poi.xssf.usermodel.XSSFTable; 
    import org.apache.poi.xssf.usermodel.XSSFWorkbook; 
    import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTable; 
    import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn; 
    import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumns; 
    import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableStyleInfo; 

    /** 
    * 
    */ 
    public class ApachePOI_ExcelTest { 

     /** 
     * @param args the command line arguments 
     */ 
     public static void main(String[] args) { 

      String outputDir = "Your Local Directory Here"; 

      // TODO code application logic here 
      HashMap<String, String> dataMap = new HashMap<>(); 

      dataMap.put("ID 1", "Dummy Name 1"); 
      dataMap.put("ID 2", "Dummy Name 2"); 
      dataMap.put("ID 3", "Dummy Name 3"); 
      dataMap.put("ID 4", "Dummy Name 4"); 

      writeExcel(dataMap, outputDir); 

     } 

     private static void writeExcel(HashMap<String, String> dataMap, String outputDir) { 
      System.out.println("Writing Excel(*.xlsx) Summary File..."); 
      XSSFWorkbook workbook = null; 
      try { 

       // Number of columns 
       int numColumns = 2; // ID and Name 
       // Number of rows 
       int numRows = dataMap.size() + 1; // +1 for header 

       // Create Workbook 
       workbook = new XSSFWorkbook(); 

       // Create Excel Table 
       XSSFSheet sheet = workbook.createSheet("Summary"); 
       XSSFTable table = sheet.createTable(); 
       table.setDisplayName("Test"); 
       CTTable cttable; 
       cttable = table.getCTTable(); 

       // Style configurations 
       CTTableStyleInfo style = cttable.addNewTableStyleInfo(); 
       style.setName("TableStyleMedium16"); 
       style.setShowColumnStripes(false); 
       style.setShowRowStripes(true); 

       // Set Tabel Span Area 
       AreaReference reference = new AreaReference(new CellReference(0, 0), new CellReference(numRows - 1, numColumns - 1)); 
       cttable.setRef(reference.formatAsString()); 
       cttable.setId(1); 
       cttable.setName("Test"); 
       cttable.setDisplayName("Test"); 
       cttable.setTotalsRowCount(numRows); 
       cttable.setTotalsRowShown(false); 

       // Create Columns 
       CTTableColumns columns = cttable.addNewTableColumns(); 
       columns.setCount(numColumns); 

       // Create Column, Row, Cell Objects 
       CTTableColumn column; 
       XSSFRow row; 

       // Add ID Header 
       column = columns.addNewTableColumn(); 
       column.setName("Column" + (1)); 
       column.setId(1); 

       // Add Name Header 
       column = columns.addNewTableColumn(); 
       column.setName("Column" + (1)); 
       column.setId(1); 

       // Add Header Row 
       XSSFRow headerRow = sheet.createRow(0); 
       headerRow.createCell(0).setCellValue("ID"); 
       headerRow.createCell(1).setCellValue("Name"); 

       int rowNumber = 1; 
       for (Map.Entry<String, String> entry : dataMap.entrySet()) { 
        String id = entry.getKey(); 
        String name = entry.getValue(); 
        row = sheet.createRow(rowNumber); 
        row.createCell(0).setCellValue(id); 
        row.createCell(1).setCellValue(name); 
        rowNumber++; 
       } 

       // Set Filter (Below three lines code somehow not working in this example, so setting AutoFilter to WorkSheet) 
    //    CTAutoFilter fltr = CTAutoFilter.Factory.newInstance(); 
    //    fltr.setRef((new AreaReference(new CellReference(0, 0), new CellReference(numRows - 1, numColumns - 1))).formatAsString()); 
    //    cttable.setAutoFilter(fltr); 
       sheet.setAutoFilter(CellRangeAddress.valueOf((new AreaReference(new CellReference(0, 0), new CellReference(numRows - 1, numColumns - 1))).formatAsString())); 

       // Freeze First Row as header Row 
       sheet.createFreezePane(0, 1, 0, 2); 

      } catch (Exception ex) { 
       System.out.println("Error while writing Excel summary file!"); 
      } finally { 
       try { 
        // Lets write the Excel File Now 
        if (workbook != null) { 
         String excelDir = outputDir + File.separator + "workbook.xlsx"; 
         try (final FileOutputStream out = new FileOutputStream(excelDir)) { 
          workbook.write(out); 
         } 
        } 
       } catch (IOException ex) { 
        System.out.println("IO Error while writing Excel summary file!"); 
       } 
      } 
     } 

    } 

用于图书馆:

OOXML-架构 - 1.1.jar

POI 3.11 -beta2-20140822.jar

POI-OOXML-3.11-beta2-20140822.jar

的xmlbeans-2.6.0.jar

+0

您是否确定自己使用的是最新版本的Apache POI? (截至撰写时为3.11测试版) – Gagravarr 2014-08-29 16:27:59

+0

@Gagravarr:是的,我使用的是完全相同的版本。 – Indigo 2014-08-29 16:59:16

+0

嗯,讨厌... Apache POI能够读取没有错误生成的文件吗?它能看到桌子吗?那么Open Office怎么样?它是否容忍文件+查看表格,或者是否在Excel中投诉? – Gagravarr 2014-08-29 17:04:41

回答

0

我有同样的问题。

深入挖掘,我发现对于XLSX包中的某些表XML数据,Excel在执行修复后将单个>更改为&gt;。来自POI的XML很有意义(使用<>来包围XML元素),所以我不知道为什么微软选择打破它。

如果您的情况相同,我不会太担心。

如果你想看看你有没有这个特殊的区别:

  1. 与POI
  2. 修复XLSX用Excel创建XLSX并保存到新的文件
  3. 开放与ZIP编辑这两个文件(例如7Zip的)
  4. 查找XL /表/ table1.xml
  5. 同时导出XML文件(POI和Excel修补)
  6. DIFF文件
+0

当由Apache POI编写时(使用应该这样做的XML库),所有内容都应该被转义。你需要改变的是什么? – Gagravarr 2014-08-29 23:50:34

+0

我调查的实例不涉及数据的更改。它是从Excel创建的XLSX文件读取并保存到新文件操作(不执行其他操作)。 POI阅读'>'转换为'>',但Excel认为这是一个不好的改变。 – 2014-08-31 05:53:29

+0

你可以从前后发布xml片段,因此我们可以看到它正在发生哪个xml元素? – Gagravarr 2014-08-31 10:00:06

0

您尚未正确创建表格。 检查:

  • 您是否在cttable中创建了标题列?
  • 您是否通过cell.setCellValue创建了相同的标题列?
  • 在末尾删除空第一集管柱(POI BUG)

    CTTable()getTableColumns()removeTableColumn(0)。。

将调试放入XSSFTable.class,方法updateHeaders()中。

如果你的表没有正确创建,然后

XSSFRow row = sheet.getRow(headerRow); 

将在

/** 
* Synchronize table headers with cell values in the parent sheet. 
* Headers <em>must</em> be in sync, otherwise Excel will display a 
* "Found unreadable content" message on startup. 
*/ 
@SuppressWarnings("deprecation") 
public void updateHeaders(){ 
    XSSFSheet sheet = (XSSFSheet)getParent(); 
    CellReference ref = getStartCellReference(); 
    if(ref == null) return; 

    int headerRow = ref.getRow(); 
    int firstHeaderColumn = ref.getCol(); 
    XSSFRow row = sheet.getRow(headerRow); 

    if (row != null && row.getCTRow().validate()) { 
     int cellnum = firstHeaderColumn; 
     for (CTTableColumn col : getCTTable().getTableColumns().getTableColumnArray()) { 
      XSSFCell cell = row.getCell(cellnum); 
      if (cell != null) { 
       col.setName(cell.getStringCellValue()); 
      } 
      cellnum++; 
     } 
    } 
} 
3

有什么问题你的代码是一个单行的存在为NULL。 “cttable.setTotalsRowCount(numRows);” 删除它,一切都会工作。 如果有疑问,请比较Excel中手动创建的某些工作表的XML定义以及使用Apache POI创建的定义。