概要
現在、テンプレートのxlsxファイルを元に、新しくcellを追加したり、既存のcellをコピーしたりしながらxlsxファイルを生成するプロジェクトを担当しています。
技術的にはRubyXLが使われているのですが、そこでなんども想定外の挙動に見舞われました・・・。
英語・日本語共に検索しても全く情報が出てこず苦労したので、ぶち当たった問題についてまとめていきたいと思います。
問題1. add_cellしたcellにchange_font_name
が効かない
内容
このようにadd_cell
でセルを追加し、change_font_name
でフォント名を変更したとします。
book[0].add_cell(0, 0, 'セルを追加します。')
book[0][0][0].change_font_name('MS 明朝')
cellのfont_nameを見たら、しっかり変更されています。
book[0][0][0].font_name
-> "MS 明朝"
しかし実際にexcelファイルを開くと、フォントが変更されていません・・・。
解決法
font.schema
をnil
にすれば動作しました。
book[0].map { |row| row&.cells&.map { |cell| cell&.change_font_name('MS 明朝') } } |
book.fonts.map { |font| font.scheme = nil } |
問題2. 既存のCellのフォントカラーから取得し、他のセルに適用できない
fill_color、font_color共に正しく取得からの適用ができないことが多々あります。
new_cell = sheet.add_cell(x, y, cell)
new_cell.change_fill(cell.fill_color)
new_cell.change_font_color(cell.font_color)
原因1 Theme Colorはfont_color
やfill_color
だとnilになる
Theme Colorsで設定した色はCellのfont_colorやfill_colorでnilになってしまいます・・・
pry(main)> book.fonts.map(&:color)
=> [#<RubyXL::Color:0x007fbb8dd87ea8 @auto=nil, @indexed=nil, @local_namespaces=[], @rgb=nil, @theme=1, @tint=nil>,
...
原因2 それ以外の方法で指定した色はRubyXL::Color
で弾かれる
それ以外の方法で色を指定すると、8桁のカラーコード(ARGB)で入れられます。
pry(main)> book[1].map{|row| row.cells.map{|cell| cell&.font_color}}
=> [["FFFFFFFF", "FFFFFFFF"],
["FFFFFFFF", "FFFFFFFF"],
...
これがRubyXL::Color
のvalidationに引っかかってしまうため、change_font_color(cell.font_color)
などでエラーになってしまいます。
module RubyXL
class Color < OOXMLObject
COLOR_REGEXP = /\A([a-f]|[A-F]|[0-9]){6}\Z/
...
def self.validate_color(color)
if color =~ COLOR_REGEXP
return true
else
raise 'invalid color'
end
end
...
問題3 既存のExcelファイルをparseし、writeしたときに、Excelファイルが壊れる
Excelファイルを開いて、保存したときに壊れることがあります。
parser = RubyXL::Parser.parse('test.xlsx')
parser.write # -> test.xlsxが壊れる
原因1 チェックボックスがあると壊れる
原因2 DefinedNameの中身次第で壊れる
ただエクセル上では見えないDefinedNameがあったりするので注意です。
(見る方法はあるかもしれませんが・・・)
原因3 merge_cellsされてる箇所をmerge_cellsする
当たり前といえば当たり前ですが、自動化してると気づかずやってしまうことがあります。
問題4 印刷範囲を変えたい
defined_nameで指定されてるため、あれば既存のシートの中身を修正、なければdefinedNameを追加します。
book.defined_names.each do |defined_name|
defined_name.reference = "Sheet1!$A$1:$B$#{@parser.book[1].count}" if defined_name.reference.start_with?('Sheet1')
end
問題5 日付をchange_contents
しても適用されない
過去記事参照) RubyXLで日付をchange_contentsしても適用されない問題
問題6 cell.change_horizontal_alignment
, cell.change_vertical_alignment
が効かない
原因調査中
問題7 ページごとの印刷範囲を変えたい
方法調査中
おわりに
ExcelのバージョンやOSなどにも依存するかと思いますが、RubyXLで起きたトラブルについてまとめてみました。
ただでさえ業務がらつかわないのに、ブラックボックスな他社ツールに依存した作業はなかなかつらみがありますね・・・。