読者です 読者をやめる 読者になる 読者になる

【Ruby】Office 2007ファイルの書き換え

Microsoft Office 2007よりファイル形式がXMLファイルの圧縮されたものになりました。
これによってファイル内容を簡単に書きかえれるようになります。
例としてExcelファイルをRubyを使って編集することにより、ショッピングサイトの価格データなどを自動入力したり、データベースなどの内容を簡単にまとめたりすることが可能となります。

しかしながら、ドキュメントが英語だったり、量が多いなどの問題があるかもしれません。(私だけかもですが・・・)
それらを解消するための要点をまとめておきます。

1.展開したファイルの圧縮について
test.xlsxというファイルを展開するとtestというフォルダ以下に
_rels, docProps, xl, [Content_Types].xml
の4ファイルが生成されます。
これらを再圧縮(zip)して再びxlsxにするわけですが、testフォルダを圧縮すると読み込めなくなります。

_rels, docProps, xl, [Content_Types].xml

の4ファイルのみを圧縮すれば正しいファイルになります。

2.ファイル読み込みについて
xmlのファイル読み込みにはREXMLというライブラリ(Ruby 1.8からRuby標準ライブラリになったようです)を使うと便利です。
以下のように読み込みます。
require 'rexml/document'
file = File.new 'test.xml'
doc = REXML::Document.new file

# データ検索は以下のように
# Excel内容はtest\xl\worksheets\sheetX.xmlファイルです。
# 今回はtest.xmlで代用します。

def search elem
   if(elem.name == "row")
     elem.each do |e|
       if(e.attributes["r"] == 'A1') # セルA1を検索します。
          e.each element do |e2|
          # エクセル表に何も値が代入されていなかった場合ここに"v"がありません。
          # その場合必要に応じてe.add_element("v")のようにつけたします。
            if(e2.name == "v")
              e2.text = "100"
            end
          end
       end
     end
   end
   # 再起で全文を検索します。
   if elem.has_elements? then
     elem.each_element |e|
       search e
     end
   end
end

search doc.root

もし、文字列を代入したい場合はA1のアトリビュートに"t"を追加し値を"str"としておきます。
e.add_attribute("t")
e.attributes["t"] = "str"

さらに文字列を書き出す場合の注意点として、XMLのファイル形式がUTF-8であることに注意します。
これはエディタなどでUTF-8に変換すればよいでしょう。

3.xml内容の検索順序について
XMLファイルの中身を見るとわかりますが、A1~Z1, A2~Z2, A3~Z3...と縦列を全部書き、次に横列となっています。
複数のセルに書き出す必要がある場合は常に縦列から検索します。

4.ファイル書き出しについて
編集したファイルを出力するためにはREXMLの関数であるwriteを使います。
このとき注意する点はファイルがオープンされていないとエラーとなる点、そしてExcel特有のヘッダを忘れないことです。
なので次のようにします。

file = open("test2.xml", 'w')

Excelファイルに必要なヘッダを書き出し

file.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n");
file.close()
file = open("test2.xml", 'a')

編集済みのデータを追加書き出し

$doc.root.write(file , -1, false)
file.close()

このファイルをsheetX.xmlファイルと置き換え圧縮することで内容を変更できます。