ODSファイル同士の比較表示
TortoiseSVN向けにWinMergeを使ったODSファイルの差分を表示するスクリプトをRubyで書いた。普段TortoiseSVNの「差分ビューアー」に登録する場合はexerbを使って実行ファイル化するんだけど、exerbを使えるRuby 1.8環境にはNokogiriをインストールしてなくて、かつ今更インストールするのも面倒。ということで、TortoiseSVNにはrubyw.exeでスクリプトを実行するように設定した。
ちなみに書いたのやこんなヤツ。以前Qiitaにあげたもの*1と作りは同じだけど、ODSファイルをTSV形式に変換するところを具体的に書いた。ODSファイルからcontent.xmlを取り出して、NokogiriのSAXパーサーを使ってTSV形式のファイルにしてからWinMergeで比較している。
require 'nokogiri' require 'zip/zipfilesystem' class Doc < Nokogiri::XML::SAX::Document attr_reader :tsv def initialize @tsv = '' @begin_of_row = false @str = '' end def characters(str) @str << str end def start_element(name, attrs = {}) case name when 'table:table-row' @begin_of_row = true when 'table:table-cell' n = (attrs.assoc('table:number-columns-repeated') || [0, 1])[1].to_i n.times do if @begin_of_row @begin_of_row = false else @tsv << "\t" end end else @begin_of_row = false end end def end_element(name, attrs = {}) case name when 'table:table-row' @tsv << "\n" when 'table:table-cell' @tsv << "\"#{@str}\"" unless @str.empty? @str.clear end end end def ods2tsv(filename) content_xml = Zip::ZipFile.open(filename) do |zf| zf.file.read('content.xml') end doc = Doc.new parser = Nokogiri::XML::SAX::Parser.new(doc) parser.parse(content_xml) doc.tsv end require 'tempfile' a = Tempfile.new('diff_ods_a_') b = Tempfile.new('diff_ods_b_') begin a.write(ods2tsv(ARGV[0])) b.write(ods2tsv(ARGV[1])) a.close b.close system 'C:/Program Files/WinMerge/WinMergeU.exe', a.path, b.path ensure a.close! b.close! end
ODSファイルのテキスト化については以前 xdoc2txtとODSファイル - 単なる日記@はてな という日記を書いたが、今回の差分表示は以前よりはマシな感じになってる(ように見える)。凝りだすときりがないのでこれはここまで。仕事に戻ります。
2013-01-28 17:17
- 行末に余分なコンマが出力されていたのを修正した。
- セルの内容によって複数回Doc#charactersが呼び出されても問題ないようにした。
- 複数回同じセルの内容が続くとうまく出力されなかったのを修正した。