2014-08-29 11 views
7

Ich versuche ResultSet in Excel (* .xlsx) Tabelle mit Apache Poi zu schreiben.ResultSet in Excel (* .xlsx) Tabelle mit Apache POI

Ungültige Tabellenobjekt Fehler in Office Excel

Doch obwohl es die Excel-Datei ohne Fehler schreibt, wenn ich versuche, es zu öffnen in Office Excel 2013, zeigt es einen Fehler und entfernt das Tabellenobjekt um nur eine Datenansicht zu geben.

Message while opening file

Message after removing errors

Hier ist der grobe Beispielcode 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!"); 
     } 
    } 
} 

Ich weiß, etwas falsch mit meinem Code, aber kann es nicht herausgefunden. Irgendeine Idee, warum das passiert, wo wäre möglicher Fehler in meinem Code.

Update 1:

Tabelle XML-Datei im Archiv Excel wenn 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> 
in Excel-Archiv

Tabelle XML-Datei mit Apache erstellt, wenn die Tabelle

<?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> 

Zusätzlich manuell erstellt Wenn ich das Excel-Archiv öffne, hat es keinen Themenordner in dem von Apache POI erstellten Ordner, aber er ist in dem einen crea vorhanden manuell in Office Excel. Seltsam.

Update 2: Beispiel ausführbarer Code (mit 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!"); 
       } 
      } 
     } 

    } 

Bibliotheken verwendet:

OOXML-schemas-1.1.jar

poi-3.11 -beta2-20140822.jar

poi-OOXML-3.11-beta2-20140822.jar

XMLBeans-2.6.0.jar

+0

Haben Sie sichergestellt, dass Sie die neueste Version von Apache POI verwenden? (3.11 Beta 2 zum Schreiben) – Gagravarr

+0

@Gagravarr: ja ich benutze genau die gleiche Version. – Indigo

+0

Hmm, nervtötend ... Ist Apache POI in der Lage, die erzeugte Datei ohne Fehler zu lesen? Kann es den Tisch sehen? Und wie wäre es mit Open Office - toleriert das die Datei + sehen Sie die Tabelle, oder verbindet es sich mit Excel bei beschweren? – Gagravarr

Antwort

0

Ich hatte das gleiche Problem.

Graben tief, fand ich, dass für einige Tabelle XML-Daten im XLSX-Paket Excel nach der Durchführung einer Reparatur ein einzelnes > zu &gt; ändert. Das XML von POI macht Sinn (verwenden Sie < und >, um XML-Elemente zu umgeben), also habe ich keine Ahnung, warum Microsoft entscheidet, es zu brechen.

Wenn es der gleiche Fall für Sie ist, würde ich mir nicht zu viele Sorgen machen.

Wenn Sie sehen möchten, wenn Sie diesen besonderen Unterschied haben:

  1. XLSX erstellen mit POI
  2. Repair XLSX mit Excel und neue Datei speichern
  3. Öffnen Sie beide Dateien mit ZIP-Editor (zB 7Zip)
  4. Suche xl/Tabellen/table1.xml
  5. Export beide XML-Dateien (POI und Excel-repariert)
  6. Diff die Dateien
+0

Wenn Apache POI geschrieben wird, sollte alles mit Escapezeichen versehen werden (es wird eine XML-Bibliothek verwendet, die das tun sollte). Was ist das Element, das du ändern musst? – Gagravarr

+0

Die Instanz, die ich untersuchte, beinhaltete keine Änderungen an den Daten. Es wurde von einer Excel-erstellten XLSX-Datei gelesen und in eine neue Dateiaktion gespeichert (keine anderen Aktionen ausgeführt). POI lesen Sie in der '>' Umwandlung in '>', aber Excel sah das als eine schlechte Änderung. –

+0

Können Sie den Ausschnitt von XML von vorher und nachher veröffentlichen, damit wir sehen können, für welches XML-Element es passiert? – Gagravarr

0

Sie haben Ihre Tabelle nicht korrekt erstellt. Prüfung:

  • Haben Sie Header-Spalten in Cttable erstellt?
  • Haben Sie die gleichen Header-Spalten durch cell.setCellValue erstellt?
  • entfernen leere erste Kopfspalte (POI BUG) am Ende

    Type gleich ctTable() getTableColumns() removeTableColumn (0),..;

Put Debug in XSSFTable.class, Methode updateHeaders().

Wenn die Tabelle nicht richtig erstellt wird, dann

XSSFRow row = sheet.getRow(headerRow); 

wird in

/** 
* 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

Was ist falsch mit Ihrem Code ist ein Vorhandensein einer einzelnen Zeile NULL sein. "cttable.setTotalsRowCount (numRows);" Entfernen Sie es und alles wird funktionieren. Vergleichen Sie im Zweifelsfall die XML-Definitionen einiger manuell in Excel erstellter Arbeitstabellen und die mit Apache POI erstellten Definitionen.

Verwandte Themen