web-dev-qa-db-ja.com

EPPlusで生成されたExcelファイルの読み取り不可能なコンテンツ

EPPlusライブラリを使用してテンプレートからExcelファイルを生成するときに、少し問題が発生します。このファイルには、次のシートのピボットテーブルに入力するために使用されるデータを含む最初のスプレッドシートがあります。

生成されたファイルを開くと、次のエラーメッセージが表示されます。「Excelで 'sampleFromTemplate.xlsx'に読み取り不可能なコンテンツが見つかりました。このワークブックのコンテンツを復元しますか?このワークブックのソースを信頼します。[はい]をクリックしてください。」

私は明らかに[はい]をクリックし、ファイルに対して行われた修復の概要と、これを含むxml形式のログファイルへのリンクを取得します。

<?xml version="1.0" encoding="UTF-8" standalone="true"?>
<recoveryLog xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
    <logFileName>error095080_01.xml</logFileName>
    <summary>Errors were detected in file  'C:\TEMP\sampleFromTemplate.xlsx'</summary>
    <repairedRecords summary="Following is a list of repairs:">
        <repairedRecord>Repaired Records: Table from /xl/tables/table1.xml part (Table)</repairedRecord>
    </repairedRecords>
</recoveryLog>

これは、ピボットテーブルに使用するデータを示すためにコードで定義した名前付き範囲( "Table1")が原因であると考えられます。 「Table1」というテンプレートにはすでに「テーブル名」がありますが、ExcelPackage.Worksheet.Namesコレクションからアクセスできないようです。 EPPlusを初めて使用し、Excelの実験があまり行われていないため、どこが間違っているのかわかりません。これが私がファイルを生成するコードのビットです:

private string GenerateFromTemplate(string fileName, string templateName, DataTable tab)
{
    FileInfo newFile = new FileInfo(string.Format("C:\\MyPath\\{0}.xlsx", fileName));
    FileInfo templateFile = new FileInfo(string.Format("C:\\MyPath\\{0}.xlsx", templateName));

    try
    {
        using (ExcelPackage pkg = new ExcelPackage(newFile, templateFile))
        {
            ExcelWorksheet sheet = pkg.Workbook.Worksheets["MyDataSheet"];
            ExcelRange range = sheet.Cells[string.Format("A1:U{0}", dt.Rows.Count)];
            pkg.Workbook.Names.Add("Table1", range as ExcelRangeBase);

            int sheetRowIndex = 2;

            foreach (DataRow row in this.dt.Rows)
            {
                sheet.Cells[sheetRowIndex, 1].Value = row["Row1"];
                sheet.Cells[sheetRowIndex, 2].Value = row["Row2"];
                [...]
                sheet.Cells[sheetRowIndex, 21].Value = row["Row21"];

                sheetRowIndex++;
            }

            pkg.Save();
            return newFile.FullName;
        }
    }
    catch (IOException ex) { return ex.Message; }
}

とにかくピボットテーブルが正しく入力されていることに注意してください。なぜこれが発生するのですか?

ありがとう:-)

15
ZipionLive

問題は解決されていませんが、今ではその理由が正確にわかりました。この「Table1」は名前付きの範囲ではなく、ワークシートの「Tables」コレクションからアクセスできるテーブルでした。

ここで問題となるのは、EPPlusのテーブルコレクションとテーブルオブジェクトの両方が読み取り専用であるため、コードからテーブルのディメンションを定義できず、ニーズに合わせてテーブルを削除したり、新しいディメンションを追加したりすることもできません。 EPPlusの作者は、メッセージがほぼ3年前のものであるため、いつか実装される可能性があるとすでに述べています( ここ および ここ )バス、それが起こることを期待することはほとんどないと思います...。

とにかく、これが同じ問題に遭遇する人の助けになることを願っています。

[編集]私はついに問題を回避する方法を思いつきました。ExcelTableオブジェクトには「TableXml」と呼ばれる書き込み可能なプロパティがあり、その範囲にはテーブルのxml定義が含まれています。私の場合の内容は次のとおりです。

<?xml version="1.0" encoding="UTF-8" standalone="true"?>
    <table dataCellStyle="Normal 2" headerRowCellStyle="Normal 2" headerRowDxfId="70" totalsRowShown="0" insertRow="1" ref="A1:U2" displayName="Table1" name="Table1" id="1" xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
        <autoFilter ref="A1:U2"/>
        <tableColumns count="21">
            <tableColumn dataCellStyle="Normal 2" name="Activity" id="1"/>
            <tableColumn dataCellStyle="Normal 2" name="Category" id="21"/>
            [...]
            <tableColumn dataCellStyle="Normal 2" name="Closed Year" id="20" dataDxfId="62"/>
        </tableColumns>
        <tableStyleInfo name="TableStyleMedium9" showColumnStripes="0" showRowStripes="1" showLastColumn="0" showFirstColumn="0"/>
</table>

ここで興味深いのは、「table」ノードと「autoFilter」ノードの「ref」属性です。これらの値を変更すると、テーブルの範囲を再定義できるためです。

私はこのように進んだ:

XmlDocument tabXml = sheet.Tables(0).TableXml;
XmlNode tableNode = tabXml.ChildNodes[1];
tableNode.Attributes["ref"].Value = string.Format("A1:U{0}", dt.Rows.Count + 1);
XmlNode autoFilterNode = tableNode.ChildNodes[0];
autoFilterNode.Attributes["ref"].Value = string.Format("A1:U{0}", dt.Rows.Count + 1);

そして今、私のExcelファイルは私のデータの実際の範囲に合う「Table1」で適切に生成されています!

8
ZipionLive

私は自分でこの問題に遭遇して修正し、他の誰かがそれに遭遇した場合に備えて私の解決策をここに置きました:

これはasp.netを使用していましたが、明らかな理由から、他の方法では適用できません。

私の問題はテーブルの範囲ではなく、Epplusがファイルを正常に生成したのではなく、サーバーの応答がページの応答をExcelファイルに追加し、明らかにファイルを無効にしていたことです。ファイルを送信した直後にサーバーの応答を終了すると、問題が修正されました。

Response.BinaryWrite(pck.GetAsByteArray());  // send the file
Response.End();
28
uaise

私はこの問題を解決するために約4時間を費やしました。私の問題と解決策は投稿にないので、将来の訪問者のために書いています。

私の問題は、Excelシートの列が重複していることが原因でした。 1つの列にスペースを追加した後、問題は解決しました。興味深いのは、MS Excelでピボットテーブルを生成したときにエラーが発生したことはなく、epplusを使用してExcelファイルにピボットテーブルを生成したときにのみ発生したことです。バグを見つけにくくする

5
Raj Kamal

各行の後に余分な列区切り文字を追加するバグがあったときに、これに遭遇しました。

head1{tab}head2{tab}
col11{tab}col21{tab}
col22{tab}col22{tab}

最後の列の後の余分なタブは、同じ方法で結果のExcelスプレッドシートを壊し、それを削除すると問題が修正されました。 LoadFromTextを使用して、テキストデータからシート全体を一度にロードしていることに注意してください。これはOPの問題ではないかもしれませんが、将来の検索者はこれが役立つかもしれません。

3
Joshua Frank

ヘッダーに特別なフォーマット(Wingdingsフォントを使用して特別な記号を表示)しているテーブルを使用してワークブックを編集するときに、この問題が発生しました。メッセージを修正するためにフォーマットを削除する必要がありました。

2
Mikhail Orlov

セットアップが異なります(ストリームを返す)が、同じ問題(テーブルレコードの破損)。私の場合、問題はExcelPackage.Save()の明示的な呼び出しでした。

using (var excelPackage = new ExcelPackage())
{
    /* ... removed code for clarity */

    // caused the stream to contain the file 2 times, 
    // save is already called by GetAsByteArray()                
    //excelPackage.Save(); 

    return new MemoryStream(excelPackage.GetAsByteArray());
}
0
Peter 375

C#とepplusを使用してテーブルからすべての行を削除すると、問題が解決しました。

0
Coder