壊れたXLSXファイルへのApacheポイのリードでXSSFTableのヘッダの名前を変更します

S.シュローダー:

私は、既存のxlsxファイルのヘッダの名前を変更しようとしています。アイデアは、XMLからExcelへのエクスポートデータをエクセルファイルを持っており、一部のユーザーが調整を行った後にXMLを再インポートすることです。

現時点で我々はすでにソート可能なテーブルを含むExcelで「テンプレート」XLSXシート(POIでXSSFTable)とXSDソースへのマッピングを作成しました。その後、我々は、POIを経由して、それをインポートすることにして保存XMLデータをマップします。我々は別の言語にこの既存のテーブルのヘッダ/列名を変換したいユーザーにシートを調整します。これは、POI 3.10-FINALで働いていたが、4.0.1へのアップグレード以来、それは時に開放壊れXLSXファイルにつながります。

私はすでにstackoverflowの上でこの質問を見つけた私は、ヘッダ(列のタイトル)の任意のセルの値を変更すると、Excelファイルが壊れてしまったが、それが答えとかなり古いされていません。しかし、私はコメントが約だったし、既存のXSSFTableを平らにしようとした、新しいシートに満たされたデータをコピーし、データに新しいXSSFTableに置いてもよいかを把握しようとしました。悲しいことに、これは私が戻って壊れたヘッダ細胞を訂正するよように、かなり複雑になるようです。また、私は離れている「テンプレート」-xslxを使用してから、POIやステップでシート全体を作成しようとしましたが、私は私たちのXSDマッピング(Excelでその開発者-ツール実装する方法を見つけ出すことはできません- >ソース- > [追加とマッピングを動的テーブル内の一部のセルにノード)

POIのアップグレードまで働いていたコードは、基本的にはこれです:

//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は右下のセルに左上からセル範囲を横断org.apache.poi.ss.util.cellwalk.CellWalkあります。

限りのxlsxは、そのマップの一部でセル名への参照を保持しますが、私はそれらすべてをつかむと、ヘッダーの名前を変更する方法を見つけ出すことができないので、私は単純に、セルの平らな値を変更するのに十分ではないと把握できて。たぶん、別のアプローチは、headernamesを変換するときにもあるのでしょうか?

アクセル・リヒター:

まあ、XSSFTable.updateHeadersがあればトリックを行う必要がありapache poi、それをやって失敗しないでしょう。

以下のすべてを使用して行われますapache poi 4.0.1

私はあなたをダウンロードしdummy_template.xlsxた後、シートのテーブルの列見出しを変更してみました。しかし、たとえ呼び出した後XSSFTable.updateHeadersに列名がXSSFTable変更されていません。だから私は、に見ていた> updateHeadersを- XSSFTable.javaをこの問題が発生していない理由を判断します。私たちはそこを見つけます:

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

シート内の対応する行が有効である場合は、列名のみが変更されますのでXMLに従ってOffice Open XML名前空間。しかし、その後にExcelバージョン(2007年後に)追加の名前空間が追加されました。この場合、行のXMLルックスが好き:

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

追加の注意x14ac:dyDescent属性を。だからこそだrow.getCTRow().validate()リターンfalse

次のコードは、あなたを取得しdummy_template.xlsx、シートの列ヘッダーの名前を変更して、武装解除バージョンを呼び出しますstatic void updateHeaders(XSSFTable table)その後result.xlsxに開くために有効です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();

 }
}

私が開いた場合はdummy_template.xlsx使用をExcel 2007して、として保存dummy_template2007.xlsx行の、XMLへの変更

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

これを使用していないとき今dummy_template2007.xlsx何手動で呼び出すXSSFTable.updateHeaders必要があります。XSSFTable.writeToによって呼び出されXSSFTable.commit、自動的にこれを行います。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=214823&siteId=1