Cambiar el nombre de los encabezados de XSSFTable con Apache Poi conduce a corruptos XLSX-archivo

S. Schroeder:

Estoy tratando de cambiar el nombre de cabeceras de un xlsx-archivo existente. La idea es tener un archivo de Excel-a exportar datos desde XML a Excel y volver a importar el XML vez que algún usuario ha hecho ajustes.

Por el momento hemos creado una "plantilla" xlsx hojas con Excel que ya contiene una tabla ordenable (XSSFTable in poi) y una asignación a un XSD-fuente. Luego importamos él a través de puntos de interés, mapa de datos XML en él y guardarlo. Para ajustar la hoja a los usuarios que queremos traducir los encabezados / columna de nombres de esta tabla existente en diferentes idiomas. Se trabajó con PDI 3.10 de final pero desde una actualización a 4.0.1 que conduce a una xlsx-archivo dañado durante la apertura.

He encontrado esta pregunta en StackOverflow ya archivo de Excel se corrompe cuando cambio el valor de cualquier celda de la cabecera (columnas de títulos) , pero no está respondiendo bastante viejo. Pero traté de averiguar lo que pueden eran los comentarios acerca y trató de aplanar la XSSFTable existente, copie los datos rellenados a una nueva hoja y poner en un nuevo XSSFTable a los datos. Lamentablemente esto parece ser bastante complicado, así que estoy de vuelta a la corrección de las células de cabecera rotos. También traté de crear toda la hoja con PDI y el paso de usar que -xslx "plantilla", pero no puedo encontrar la manera de poner en práctica nuestra XSD-Mapping (en Excel sus desarrolladores Herramientas -> Fuente -> Añadir y luego mapeo los nodos a algunas células en una tabla dinámica)

El código que funcionó hasta que la actualización del PDI es básicamente el siguiente:

//Sheet is the current XSSFSheet
//header is a Map with the original header-name from the template mapped to a the new translated name
//headerrownumber is the row containing the tableheader to be translated

 public static void translateHeaders(Sheet sheet,final Map<String,String> header,int headerrownumber) {
  CellRangeAddress address = new CellRangeAddress(headerrownumber,headerrownumber,0,sheet.getRow(headerrownumber).getLastCellNum());  //Cellrange is the header-row

        MyCellWalk cellWalk = new MyCellWalk (sheet,address);
        cellWalk.traverse(new CellHandler() {
            public void onCell(Cell cell, CellWalkContext ctx) {
                String val = cell.getStringCellValue();
                if (header.containsKey(val)) {
                    cell.setCellValue(header.get(val));
                }
            }
        });
}

MyCellWalk es un org.apache.poi.ss.util.cellwalk.CellWalk que atraviesa el rango de celdas desde la parte superior izquierda a la celda derecha inferior.

Por lo que pude averiguar que no es suficiente simplemente cambiar el valor plana de la celda porque xlsx mantiene referencias a la nombrecélula en algunos de sus mapas, pero no puedo encontrar la manera de agarrar a todos y cambiar el nombre de la cabecera. Tal vez también hay otro enfoque en la traducción de los headernames?

Axel Richter:

Así, los XSSFTable.updateHeaders debe hacer el truco si apache poino dejaría de hacerlo.

Todo lo siguiente se hace usando apache poi 4.0.1.

He descargado el dummy_template.xlsxy luego intentado cambiar los encabezados de columna de la tabla en la hoja. Pero incluso después de llamar a XSSFTable.updateHeaderslos nombres de columna en la XSSFTableque no ha cambiado. Así que tenía una mirada en XSSFTable.java -> updateHeaders para determinar por qué esto no sucede. Allí nos encontramos con:

if (row != null && row.getCTRow().validate()) {
 //do changing the column names
}

Por lo que los nombres de columna sólo se pueden modificar si la fila correspondiente en la hoja es válida XMLde acuerdo con Office Open XMLespacios de nombres. Sin embargo, en posteriores Excelversiones se añadieron (después de 2007) espacios de nombres adicionales. En este caso de la fila XMLse ve así:

<row r="4" spans="1:3" x14ac:dyDescent="0.25">

Tenga en cuenta el adicional x14ac:dyDescentatributo. Es por eso que row.getCTRow().validate()los retornos false.

El código siguiente obtiene su dummy_template.xlsx, cambia el nombre de los títulos de las columnas en la hoja y luego llama a una versión desarmada static void updateHeaders(XSSFTable table). Después de que el result.xlsxes válido para la apertura en Excel.

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.ss.util.cellwalk.*;

import org.apache.poi.xssf.usermodel.*;

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

import java.io.*;
import java.util.*;

class ExcelRenameTableColumns {

 static void translateHeaders(Sheet sheet, final Map<String,String> header, int headerrownumber) {
  CellRangeAddress address = new CellRangeAddress(
   headerrownumber, headerrownumber, 
   0, sheet.getRow(headerrownumber).getLastCellNum());

  CellWalk cellWalk = new CellWalk (sheet, address);
  cellWalk.traverse(new CellHandler() {
   public void onCell(Cell cell, CellWalkContext ctx) {
    String val = cell.getStringCellValue();
    if (header.containsKey(val)) {
     cell.setCellValue(header.get(val));
    }
   }
  });
 }

 static void updateHeaders(XSSFTable table) {
  XSSFSheet sheet = (XSSFSheet)table.getParent();
  CellReference ref = table.getStartCellReference();

  if (ref == null) return;

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

System.out.println(row.getCTRow().validate()); // false!

  if (row != null /*&& row.getCTRow().validate()*/) {
   int cellnum = firstHeaderColumn;
   CTTableColumns ctTableColumns = table.getCTTable().getTableColumns();
   if(ctTableColumns != null) {
    for (CTTableColumn col : ctTableColumns.getTableColumnList()) {
     XSSFCell cell = row.getCell(cellnum);
     if (cell != null) {
      col.setName(formatter.formatCellValue(cell));
     }
     cellnum++;
    }
   }
  }
 }

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

  String templatePath = "dummy_template.xlsx";
  String outputPath = "result.xlsx";

  FileInputStream inputStream = new FileInputStream(templatePath);
  Workbook workbook = WorkbookFactory.create(inputStream);
  Sheet sheet = workbook.getSheetAt(0);

  Map<String, String> header = new HashMap<String, String>();
  header.put("textone", "Spalte eins");
  header.put("texttwo", "Spalte zwei");
  header.put("textthree", "Spalte drei");

  translateHeaders(sheet, header, 3);

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

  updateHeaders(table);

  FileOutputStream outputStream = new FileOutputStream(outputPath);
  workbook.write(outputStream);
  outputStream.close();
  workbook.close();

 }
}

Si abro el dummy_template.xlsxuso Excel 2007y luego guardar como dummy_template2007.xlsx, de la fila de XMLcambios a

<row r="4" spans="1:3">

Ahora, cuando el uso de este dummy_template2007.xlsxsin manualmente llamando a la XSSFTable.updateHeaderses necesario. El XSSFTable.writeTo la cual es invocado XSSFTable.commitlo hace automáticamente.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=214826&siteId=1
Recomendado
Clasificación