0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

細かすぎて伝わらない openpyxl の仕様について ~Python製Excelファイルが他社アプリで読み込まれなかった理由~

Last updated at Posted at 2025-07-31

背景

業務用データを AWS Lambda 上で Excel ファイルとして生成し、他社のExcelファイルを読み込んで処理するデスクトップアプリケーション にアップロードするという処理を開発していました。

当初、PHPSpreadsheet を使って生成した Excel ファイルをアップロードしたところ、問題なく読み込まれました。

その後、Lambda によるサーバーレス化を進める中で、Python を使って同等の機能を実現する必要が生じました。 そこで openpyxl を用いて同じ構造の Excel ファイルを生成し、同アプリにアップロードしたところ、

❌ ファイル形式が不正です

というエラーが表示されました。

Excel自体では正常に開くことができ、レイアウトも PHPSpreadsheet 版とほぼ同一でした。 にもかかわらず、アプリ側では受け付けてもらえません。

この現象について調査を行い、Excelファイル内部の構造に違いがあることが判明しました。


問題の再現コード

from openpyxl import Workbook

wb = Workbook()
ws = wb.active
ws.append(["商品名", "カテゴリ", "個数"])
ws.append(["いい感じの本", "実用書", "10"])
wb.save("output.xlsx")

このExcelファイルをアップロードしたところ、

❌ ファイル形式が不正です

さらに不可解なことに、Excel上で最後の行を削除して保存し直したファイルは問題なく読み込まれるという現象も確認されました。


XMLレベルで調査

.xlsx ファイルを .zip に変換し、sheet1.xml を直接調査したところ、openpyxl が生成したセルの構造は次のようになっていました:

<c r="B2" t="inlineStr">
  <is>
    <t>1</t>
  </is>
</c>

この t="inlineStr" 属性は「セルの文字列がインラインで直接書かれている」ことを意味します。

なぜこれが問題なのか?

一部の読み込み専用アプリケーションは、インライン文字列(inlineStr) に対応しておらず、 sharedString(t="s")形式のみを想定して実装されていることがあります。

実際に PHPSpreadsheet や Excel GUI で保存したファイルでは、次のような記述になります:

<c r="B2" t="s">
  <v>1</v>
</c>

この場合、文字列の中身は sharedStrings.xml に格納され、セルにはそのインデックスだけが入ります。


解決策: xlsxwriter を使う

Python で sharedString 形式を出力するためには、xlsxwriter を使うのが確実です。

import xlsxwriter
from io import BytesIO

wb_buffer = BytesIO()
wb = xlsxwriter.Workbook(wb_buffer, {'in_memory': True})
ws = wb.add_worksheet()

rows = [
    ["商品名", "カテゴリ", "個数"],
    ["いい感じの本", "実用書", "10"]
]

for i, row in enumerate(rows):
    for j, val in enumerate(row):
        ws.write(i, j, val)

wb.close()

このように xlsxwriter を使えば:

  • すべてのセルが sharedString 形式で書き込まれる
  • UsedRange も過不足なく出力される
  • 不要な空行や空セルも書き込まれない

結果、アプリ側でも正常に取り込まれるExcelファイルになります。


教訓

  • openpyxl は便利だが、セル出力形式(inlineStr vs sharedString)に関する仕様が暗黙的なため注意が必要。
  • Excel GUI や PHPSpreadsheet と見た目が同じでも、内部構造が違うことがある。
  • 相手側アプリが仕様通りに動かないことを前提に設計する覚悟も必要。
  • .xlsx.zip にして sheet1.xmlsharedStrings.xml を確認するのがトラブル調査の第一歩。
  • 特に読み込み側が古い・特殊・閉じたアプリケーションである場合、xlsxwriter の利用が無難な選択肢

以上、「意外と落とし穴の多いExcelファイル生成とその仕様」についての一例でした。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?