Repaired Records: Table from /xl/tables/table1.xml part (Table)

653 Views Asked by At

I am looking for code that will display the totals row in an excel table at the end using apache poi.

To simplify the problem, I implemented sample code to generate a table in an Excel sheet with some dummy data.

The code is working, but when I open the generated Excel workbook, I receive the warning message shown below.

Is there a problem with the code?

import java.awt.Desktop;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.AreaReference;
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;

public class CreateTableExample {

    public static void main(String[] args) {
        try (Workbook workbook = new XSSFWorkbook()) {
            Sheet sheet = workbook.createSheet("Sheet1");

            // Create headers
            Row headerRow = sheet.createRow(0);
            for (int i = 0; i < 3; i++) {
                Cell headerCell = headerRow.createCell(i);
                headerCell.setCellValue("Header " + (i + 1));
            }

            // Create sample data
            for (int i = 1; i <= 10; i++) {
                Row dataRow = sheet.createRow(i);
                for (int j = 0; j < 3; j++) {
                    Cell dataCell = dataRow.createCell(j);
                    dataCell.setCellValue( (j + 1));
                }
            }

            Row totalRow = sheet.createRow(11);
            totalRow.createCell(0).setCellValue("Total");;

            
            // Define the data range for the table
            AreaReference areaReference = new AreaReference("A1:C12", SpreadsheetVersion.EXCEL2007);

            // Create the table
            XSSFTable table = ((XSSFSheet) sheet).createTable(areaReference);
            String tableName = "MyTable";
            table.setName(tableName);
            CTTable ctTable = table.getCTTable();
            ctTable.setDisplayName(tableName);
            ctTable.setId(1);
            ctTable.setTotalsRowShown(true);
            ctTable.setTotalsRowCount(1);
            // Set the table style
            table.getCTTable().addNewTableStyleInfo();
            table.getCTTable().getTableStyleInfo().setName("TableStyleMedium9");

            
            
            String format = String.format("SUBTOTAL(109,%s[%s])",tableName,  "Header 2");
            totalRow.createCell(1).setCellFormula(String.format("SUBTOTAL(109,%s[%s])",tableName,  "Header 2"));
            totalRow.createCell(2).setCellFormula(String.format("SUBTOTAL(109,%s[%s])",tableName,  "Header 3"));
            
            
            
            // Save the workbook
            try (FileOutputStream fileOut = new FileOutputStream("workbook_with_table.xlsx")) {
                workbook.write(fileOut);
            }
            
            Desktop.getDesktop().open(new File("workbook_with_table.xlsx"));

            System.out.println("Excel file with table created successfully.");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

enter image description here

enter image description here

enter image description here

1

There are 1 best solutions below

3
On BEST ANSWER

Welcome to the brave world of Microsoft's Office Open XML. For tables one always needs both. Once the settings in table XML and second the settings in the corresponding worksheet.

In terms of a totals row, that are the totals row label for first table column and the corresponding string cell value in sheet and the totals row functions for the other table columns and the corresponding formulas in sheet.

...
        // add totals row to table
        
        Row totalsRow = sheet.createRow(11);
        // set totals row label for table column 0
        table.getCTTable().getTableColumns().getTableColumnList().get(0).setTotalsRowLabel("Totals");
        // set sheet cell value for this            
        totalsRow.createCell(0).setCellValue("Totals");;

        table.getCTTable().setTotalsRowShown(true);
        table.getCTTable().setTotalsRowCount(1);

        //avoid bug in version 5.2.0 to 5.2.3
        //https://stackoverflow.com/questions/52877212/expanding-an-existing-table-in-excel-using-apache-poi/52904452#52904452
        ((XSSFWorkbook)workbook).setCellFormulaValidation(false);

        // set totals row function for table column
        table.getCTTable().getTableColumns().getTableColumnList().get(1).setTotalsRowFunction(
            org.openxmlformats.schemas.spreadsheetml.x2006.main.STTotalsRowFunction.SUM);   
        // set sheet cell formula for this          
        totalsRow.createCell(1).setCellFormula(String.format("SUBTOTAL(109,%s[%s])",tableName,  "Header 2"));
            
        // set totals row function for table column
        table.getCTTable().getTableColumns().getTableColumnList().get(2).setTotalsRowFunction(
            org.openxmlformats.schemas.spreadsheetml.x2006.main.STTotalsRowFunction.SUM);   
        // set sheet cell formula for this          
        totalsRow.createCell(2).setCellFormula(String.format("SUBTOTAL(109,%s[%s])",tableName,  "Header 3"));
...

Complete example:

import java.awt.Desktop;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFTable;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class CreateTableExample {

    public static void main(String[] args) {
        try (Workbook workbook = new XSSFWorkbook()) {
            Sheet sheet = workbook.createSheet("Sheet1");

            // Create headers
            Row headerRow = sheet.createRow(0);
            for (int i = 0; i < 3; i++) {
                Cell headerCell = headerRow.createCell(i);
                headerCell.setCellValue("Header " + (i + 1));
            }

            // Create sample data
            for (int i = 1; i <= 10; i++) {
                Row dataRow = sheet.createRow(i);
                for (int j = 0; j < 3; j++) {
                    Cell dataCell = dataRow.createCell(j);
                    dataCell.setCellValue( (j + 1));
                }
            }

            // Define the data range for the table
            AreaReference areaReference = new AreaReference("A1:C12", SpreadsheetVersion.EXCEL2007);

            // Create the table
            XSSFTable table = ((XSSFSheet) sheet).createTable(areaReference);
            // Set the table style
            table.getCTTable().addNewTableStyleInfo();
            table.getCTTable().getTableStyleInfo().setName("TableStyleMedium9");
            
            String tableName = "MyTable";
            table.setName(tableName);
            table.getCTTable().setDisplayName(tableName);

            // add totals row to table
            
            Row totalsRow = sheet.createRow(11);
            // set totals row label for table column 0
            table.getCTTable().getTableColumns().getTableColumnList().get(0).setTotalsRowLabel("Totals");
            // set sheet cell value for this            
            totalsRow.createCell(0).setCellValue("Totals");;

            table.getCTTable().setTotalsRowShown(true);
            table.getCTTable().setTotalsRowCount(1);
            
            //avoid bug in version 5.2.0 to 5.2.3
            //https://stackoverflow.com/questions/52877212/expanding-an-existing-table-in-excel-using-apache-poi/52904452#52904452
            ((XSSFWorkbook)workbook).setCellFormulaValidation(false);

            // set totals row function for table column
            table.getCTTable().getTableColumns().getTableColumnList().get(1).setTotalsRowFunction(
                org.openxmlformats.schemas.spreadsheetml.x2006.main.STTotalsRowFunction.SUM);   
            // set sheet cell formula for this          
            totalsRow.createCell(1).setCellFormula(String.format("SUBTOTAL(109,%s[%s])",tableName,  "Header 2"));
                
            // set totals row function for table column
            table.getCTTable().getTableColumns().getTableColumnList().get(2).setTotalsRowFunction(
                org.openxmlformats.schemas.spreadsheetml.x2006.main.STTotalsRowFunction.SUM);   
            // set sheet cell formula for this          
            totalsRow.createCell(2).setCellFormula(String.format("SUBTOTAL(109,%s[%s])",tableName,  "Header 3"));
            
            // Save the workbook
            try (FileOutputStream fileOut = new FileOutputStream("workbook_with_table.xlsx")) {
                workbook.write(fileOut);
            }
            
            Desktop.getDesktop().open(new File("workbook_with_table.xlsx"));

            System.out.println("Excel file with table created successfully.");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}