Расширение существующей таблицы в Excel с использованием Apache POI - PullRequest
0 голосов
/ 18 октября 2018

У меня есть таблица в Excel с формулами, в которые я хотел бы добавить данные.

table

Моим мотивом для этого является тот факт, что таблицы в Excel могут динамически расширяться до диапазона данных, который вы добавляете к ним, то есть строки формулыавтоматически не отставать от количества строк данных.

Однако мне трудно определить, возможно ли это с помощью apache-POI.

Одна вещь, которую я собирался попробовать (см.код ниже) должен был расширить AreaReference таблицы, чтобы охватить данные, однако и AreaReference(CR,CR2); (как используется в этом примере) и AreaReference(CR,CR2, SpreadsheetVersion.EXCEL2007) (видно в документации apache *)1018 *) дать "конструктор не определен".

Понятия не имею, что вызывает эту конструкторскую ошибку, поскольку у меня org.apache.poi.ss.util импортировано.

Другая опция в apache docs AreaReference(java.lang.String reference) позволяетя компилирую и запускаю, но вместо этого выдает ошибку «NoSuchMethod».

        List<XSSFTable> tableList = spreadSheet.getTables();
        CellReference CR = new CellReference(0, 0); 
        CellReference CR2 = new CellReference(5, 2);
        AreaReference my_data_range = new AreaReference(CR,CR2);
        tableList.get(0).setArea(my_data_range);

Любая помощь будет оценена.

1 Ответ

0 голосов
/ 20 октября 2018

Основная проблема, связанная с использованием apache poi до сих пор, заключается в том, что он не готов к использованию без подробных знаний о Microsoft Office как таковых и о хранении файлов Microsoft Office.Многие вещи готовы только наполовину, и в новых версиях часто возникают регрессии (снова появляются ошибки, которые уже были устранены).

Итак, ваше требование: «Расширение существующей таблицы в Excel с использованием Apache POI» невозможнотолько просто используя apache poi.Нужно знать, что Office Open XML файлы *.xlsx - это просто ZIP архивы, которые можно распаковать.А после распаковки находим /xl/tables/table1.xml для хранения таблицы.Это XML мы можем проанализировать и сравнить с XML, который был создан с использованием Excel s GUI.Таким образом, мы можем найти проблемы, которые возникают из-за недостатков apache poi.То же самое с XML в /xl/tables/sheet1.xml.

Также нам нужно знать, что apache poi основан на низкоуровневых классах ooxml-schemas.Частично нам нужно использовать эти классы из-за половины готовности apache poi.В следующем примере нам понадобится ooxml-schemas-1.4.jar дополнительно, потому что apache poi poi-ooxml-schemas-4.0.0.jar не включает org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableFormula до сих пор.К сожалению, нет документации о ooxml-schemas публично доступной.Поэтому нам нужно скачать исходники и сделать javadoc наши собственные.

Следующий пример работает для меня с использованием apache poi 4.0.0.Если у вас возникают проблемы во время компиляции или запуска, причина может заключаться в том, что несколько разных версий apache poi jar s находятся в пути к классам во время компиляции и / или выполнения. Не смешивайте разные версии apache poi .Кроме того, как уже было сказано, моему коду требуется полный файл jar всех схем ooxml-schemas-1.4.jar .

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.ss.SpreadsheetVersion;

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

import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn;

class ExcelExpandingTable {

 static void addRowToTable(XSSFTable table) {

   int lastTableRow = table.getEndCellReference().getRow();
   int totalsRowCount = table.getTotalsRowCount();
   int lastTableDataRow = lastTableRow - totalsRowCount;

   // we will add one row in table data
   lastTableRow++;
   lastTableDataRow++;

   // new table area plus one row
   AreaReference newTableArea = new AreaReference(
                                 table.getStartCellReference(), 
                                 new CellReference(
                                  lastTableRow, 
                                  table.getEndCellReference().getCol()
                                 ),
                                 SpreadsheetVersion.EXCEL2007
                                );

   // new table data area plus one row
   AreaReference newTableDataArea = new AreaReference(
                                     table.getStartCellReference(), 
                                      new CellReference(
                                       lastTableDataRow, 
                                       table.getEndCellReference().getCol()
                                      ),
                                      SpreadsheetVersion.EXCEL2007
                                    );

   XSSFSheet sheet = table.getXSSFSheet();
   if (totalsRowCount > 0) {
    //if we have totals rows, shift totals rows down
    sheet.shiftRows(lastTableDataRow, lastTableRow, 1);

    // correcting bug that shiftRows does not adjusting references of the cells
    // if row 3 is shifted down, then reference in the cells remain r="A3", r="B3", ...
    // they must be adjusted to the new row thoug: r="A4", r="B4", ...
    // apache poi 3.17 has done this properly but had have other bugs in shiftRows.
    for (int r = lastTableDataRow; r < lastTableRow + 1; r++) {
     XSSFRow row = sheet.getRow(r); 
     if (row != null) {
      long rRef = row.getCTRow().getR();
      for (Cell cell : row) {
       String cRef = ((XSSFCell)cell).getCTCell().getR();
       ((XSSFCell)cell).getCTCell().setR(cRef.replaceAll("[0-9]", "") + rRef);
      }
     }
    }
    // end correcting bug

   }

   // if there are CalculatedColumnFormulas do filling them to the new row
   XSSFRow row = sheet.getRow(lastTableDataRow); if (row == null) row = sheet.createRow(lastTableDataRow);
   for (CTTableColumn tableCol : table.getCTTable().getTableColumns().getTableColumnList()) {
    if (tableCol.getCalculatedColumnFormula() != null) {
     int id = (int)tableCol.getId();
     String formula = tableCol.getCalculatedColumnFormula().getStringValue();
     XSSFCell cell = row.getCell(id -1); if (cell == null) cell = row.createCell(id -1);
     cell.setCellFormula(formula);
    }
   }

   table.setArea(newTableArea);

   // correcting bug that Autofilter includes possible TotalsRows after setArea new
   // Autofilter must only contain data area
   table.getCTTable().getAutoFilter().setRef(newTableDataArea.formatAsString());
   // end correcting bug

   table.updateReferences();

 }

 public static void main(String[] args) throws Exception {
  try (Workbook workbook = WorkbookFactory.create(new FileInputStream("SAMPLE.xlsx"));
       FileOutputStream out = new FileOutputStream("SAMPLE_NEW.xlsx")) {

   XSSFSheet sheet = ((XSSFWorkbook)workbook).getSheetAt(0);
   XSSFTable table = sheet.getTables().get(0);

   addRowToTable(table);

   workbook.write(out);
  } 
 }
}
...