TL;DR
/xl/drawings/drawing1.xml
の中身はXMLなので、壊れた要素を特定して取り除くことで開けるようになるよ。
図が絵がたくさんあるファイルだったので、1つずつ順番に取り除いたファイルを生成するプログラムをRubyで書いたよ。
あらすじ
せっせと作ったExcelファイル。完成して他の人に送ったら「開けないんですけど」との連絡が。
そんなわけあるかい、、と思い、手元のオリジナルを開くと、「一部に問題が見つかりました。」とのこと。
可能な限り内容を修復してほしいので、「はい(Y)」を選択
図形や画像ファイルが綺麗さっぱり消えていました。
こんなに悲しいことがあるだろうか。(いや、ない)
なので、紆余曲折の後、イカれたメンバーを特定してくれるやつを作成したのであった。
調査
しばらくインターネットの海を漂うと、同じ問題に直面した人がいるということが分かった。
OpenOfficeを試す
Excel2010で壊れた図形を復活させてみたを参考にOpenOfficeで開き直すと、確かに開くことができた。
ただ、図の矢印や画像のアスペクト比がぐちゃくちゃになっていて、とても、完全復活といえる代物ではなかった。
テキストベースのexcelなら、この方法で復活させて完了で良い気もするが、今回は図や絵がふんだんに使われていたのでPass。
ちなみに、OpenOfficeではxlsx形式で保存することができず、xls形式で保存することになるため注意が必要。
drawing1.xmlから壊れている図を特定する
エクセルが開かないを読むと
- xlsxの実態はzipファイルで、拡張子を変更すると解凍することができるらしい
- /xl/drawings/drawing1.xml というファイルの中にある
<xdr:twoCellAnchor>
という要素で図や絵を表現しているらしい - 壊れた
<xdr:twoCellAnchor>
を取り除くことで、壊れていない部分は復旧させることが可能
ということらしい。ふむふむ。
てことは、例えば、<xdr:twoCellAnchor>
要素を半分に分けて、エラーが起こるかどうかを確認する、発生したら発生した方を更に半分にして、、、みたいに、二分探索していけばいつかはたどり着くんだろうけど、、、
- 拡張子をxlsxからzipに変更
- 解凍
- フォルダ内のdrawing1.xmlを編集 <= インデントや改行が無いので、ツールが無いと結構しんどい
- 圧縮
- 拡張子をzipからxlsxに変更
- excelで開いてみる
- 壊れていれば、再び3から
- (゚д゚)ウマー
という手順を黙々と行う必要がある。
今回は、170個ぐらい図や絵が貼ってあるExcelファイルだったので、[log_2 170] + 1 = 8 で 最大8回繰り返せば破損箇所が特定できそうだ。
ただ、こんな地道な作業8回もやりたくない、、、
ということで、イカれたメンバーを特定してくれるやつを作ることにしました。
イカれたメンバーを特定してくれるやつ
イカれたメンバーを特定してくれるやつを作りました。
結果的に線形探索になりました。
急いでいたので、Rubyで書きました。
が、Rubyの記述力に私の実力が追いついていないため、冗長です。え?リファクタリング?できたらする。
やっていること
<xdr:twoCellAnchor>
、もしくは<xdr:oneCellAnchor>
要素をdrawing1.xmlに1つ追加しては、その都度rebuild_[連番].xlsxを生成する
使い方
- RubyのインストールされたOSを準備する
-
gem install rubyzip
する - githubからイカれたメンバーを特定してくれるやつを取得する
- targetフォルダにxlsxファイルをzipにして解凍したファイルの中身を配置する
-
$ ruby ./src/rebuild_excel_book.rb
する - resultフォルダに生成されたExcelファイルを上から叩いて、イカれたメンバーを特定するぜ
感想
-
<xdr:twoCellAnchor>
だけでなく、<xdr:oneCellAnchor>
も存在するようだ。更なる調査が必要 - xmlは改行が入っていても問題ないので、
(</xdr:oneCellAnchor)
や(</xdr:twoCellAnchor)
を\r\n$1
で置換してしまえば読みやすくなる - xmlは
<!-- -->
でコメントアウトできるので、drawing1.xmlの内容が少なければ、手作業で怪しい箇所をコメントアウトして確認しても大した手間じゃないかも(というか、要素1つ1つをコメントアウトしていって、開くことができるファイルを探すほうが賢かったかも) -
<xdr:twoCellAnchor>
の子要素に一意となるid的な属性を持っていることに後から気付いた。rebuildするファイルのファイル名をidにすると、特定した後、壊れた要素を削除するのが楽になるかも - Excelがdrawing1.xmlを読み込むモジュールが分かれば、エラーが発生するかどうかの判定ができそうなので、該当箇所の特定と削除を1つのプログラムで完結できそう(となるとVBSかC#が適しているかな)