FrontPage  Index  Search  Changes  Login

exlap_cの使い方

exlap_c 〜 xmlss作成用rubyライブラリ (ver 1.3)

最終更新日: 2011/06/28

最新バージョン ver 1.3: exlap_c130.zip


1. 目的、特徴

 exlap_cは、Excelで扱えるxmlスプレッドシート(以下、 xmlssと記述)を作成するために設けたライブラリです。

 xmlssは、test.xml のように拡張子が .xml のファイルで、Excel2002以降で扱えます。Excel2003以降がインストールされている環境では、xmlssをクリックするだけでExcelが起動します。

 当ライブラリは、rubyの配列をxmlssに変換するのが機能の中核です。ここでいう配列は、各要素をary[i][j]の形で参照できる「配列の配列」です。変議場、以下ではこのような配列を2次元配列と標記します。

 特徴を列挙すると次のとおり。

  • csv、webのtable部分、xmlssを読み込んで、2次元配列に変換する仕組みを含んでいます。また、その2次元配列をcsv、web、xmlssとして書き出すメソッドも用意してあります。つまり、csv、web、xmlssの3種類を相互に変換できます。
  • 基本的にはrubyの標準添付ライブラリ nkf, csv, open-uri, rexml を使っているだけなので、MS-Windowsに限らずいろいろなOSで使えます(Webを扱う時は htmlパーサとしてnokogiriかhpricotが必要)。
  • いわゆる「001問題」(左側の0が消えてしまう)とか「セル結合」に対応しています。
  • font(文字の大きさや色)、alignment(文字の配置)、borders(罫線)などの指定が可能です。
  • 列の幅、行の高さを指定できます。
  • Excelの計算式や関数をセルに埋め込むことができます。

-----------------------------------------------------------------------------

2. 動作環境

 ruby ver 1.8.x または 1.9.x で動作します。

 rubyが使える環境であれば、OSは問わないと思います。

 動作確認は、次の環境で行いました。

  • ruby 1.8.7p302: Windows XP|VISTA
  • ruby 1.8.7p248: FreeBSD 7.2
  • ruby 1.9.1p429: Windows XP|VISTA

 なお、webの解析には htmlパーサとして hpricot または nokogiri を用います。これらは、rubyのライブラリです。webのtableを扱うメソッドを使う時は、少なくともどちらか1つを予めインストールしておく必要があります。

 hpricot ver 0.8.2 および nokogiri ver 1.4.3.1 で動作確認しました。

 ruby ver 1.9.x では hpricot を使えないようです(私のところでは利用できません)。1.9系ではnokogiriを使うのがいいと思います。

-----------------------------------------------------------------------------

3. ライブラリの漢字コード

 ライブラリは、漢字コード別に3種類あります。

 exlap_s.rb(Shift_JIS版), exlap_e.rb(euc-jp版), exlap_u.rb(utf-8版)の3種です。

 用いる漢字コードに応じて、3種類のどれかをrequireします。

 あるいは、ruby v1.8系の場合、exlap_c.rbをrequireすれば、$KCODEの値に応じて3種類のうちのどれかがrequireされます。判別できない時は、utf-8版がrequireされます。

 ruby v1.9系では、exlap_c.rbをrequireした場合、常に utf-8版がrequireされます。

 v1.9系の場合、ライブラリの漢字コードと、それを呼び出す側の漢字コードが違っていても、動作に支障はありません。ただ、個々のセル内容を読み書きするような細かな処理の場合、漢字コード変換等が必要になります。

 当ドキュメントの中で掲げているサンプル程度であれば、Shift_JISのままで問題なく動きます。

 ちなみに、ライブラリの漢字コードを自分で変換する場合は、2箇所を書き換えてコード変換します。

 exlap_u.rbの第1行目にある「coding: utf-8」を「coding: Shift_JIS」に変更して、

 9行目辺りの「$ExlapBaseC = 'w'」の 'w' を 's' に変更し、

 exlap_u.rbの漢字コードをまるごとShift_JISに変換すれば、exlap_s.rbになります。

 ruby v1.9 において、現状では、Windows-31J に対応できないと思います。

 ライブラリ内での漢字コード変換は、nkfで行っています。v1.9のencoding機能は使っていません。

-----------------------------------------------------------------------------

4. ライブラリの置き場所

 当ライブラリを利用する場合、一連のexlap_*.rbをカレントディレクトリに置きか、または、rubyの library path が通ったディレクトリに置きます。(環境によってはカレントディレクトリに置いても使えない場合があるので注意して下さい。)

 例えば、ruby.exe(v1.8系)が C:\ruby\bin\ の下にある場合でいうと、

   C:\ruby\lib\ruby\site_ruby\1.8\

の下に exlap_*.rb を置きます。そうしておけば、どのディレクトリからでもライブラリとして利用できます。

-----------------------------------------------------------------------------

5. とりあえず試してみる

(1) webのtable、csvをxmlssとして書き出す

 当ライブラリの最も中心となるクラスは、ワークブックを表現する ExlBook です。

 このクラスには、csv、webのtable、xmlssを取り込むメソッドが含まれています。ここでいうwebのtableは、入れ子になっていないtableです。つまりtableの中に更にtableが含まれているものは除きます。

 また、xmlss, csv, web を書き出すメソッドもあります。

 webのtableをxmlssとして書き出すためのサンプルを掲げてみます。

   −−−− ここから
   #! ruby -Ks
     # coding: Shift_JIS
   require "exlap_c"
   url = "http://www.videor.co.jp/data/ratedata/top10.htm"
   wb = ExlBook.new
   wb.push(url)
   wb.output_xml "videor.xml"
   −−−− ここまで

 上記は、webのurlを与えてxmlssを出力させていますが、urlの代わりにhtmlソースが記録された文字列を与えてもかまいません。

 また、csvファイルの名前、もしくは、csvデータが記録された文字列を与えることもできます。

   −−−− ここから
   #! ruby -Ks
     # coding: Shift_JIS
   require "exlap_c"
   csv_str = "awk,perl\n" + "python,ruby\n"
   wb = ExlBook.new
   wb.push(csv_str)
   wb.output_xml "test.xml"
   −−−− ここまで

 ExlBookクラスのpushメソッドは、url, html_string, csv_filename, csv_string を受け付けます。

 通常、それらは正しく処理されると思いますが、うまくいかない場合は、

 url, html_string については web_push (別名 push_web)

 csv_filename, csv_string については csv_push (別名 push_csv)

をそれぞれ試してみて下さい。

 なお、xmlssを取り込む時は必ず xml_push(別名 push_xml)メソッドを用います。pushメソッドは使えません。このメソッドに渡す引数は、xmlssのファイル名、url、文字列のどれかです。引数は1つのみ渡します。カンマで区切って複数指定することはできません。ただし、メソッドを複数回呼び出すて、複数のxmlssを取り込むことは可能です。

* pushメソッドには、2次元配列およびワークシートを表すExlSheetオブジェクト(後述)を引数として渡すこともできます。

* exlap_cよりも前に FasterCSVをrequireしておけば、標準のcsvライブラリでなく、FasterCSVの方を用います。ただし、FasterCSVは、ruby ver 1.9以降では使えないようなので、rubyのバージョンが1.9以降では標準のcsvを使うようにしてあります。

(2) 2次元配列をxmlssとして書き出す

 ExlBookクラスのpushメソッドには、2次元配列を与えることもできます。個々のセルに関する情報の集合が2次元配列です。

   −−−− ここから
   #! ruby -Ks
     # coding: Shift_JIS
   require "exlap_c"
   ary = [
       ['awk',    'perl'],
       ['python', 'ruby']]
   wb = ExlBook.new
   wb.push(ary)
   wb.output_xml "test.xml"
   −−−− ここまで

 空欄のセルは nil、空白行は [] にします。例えば

   ary = [
       ['awk',    nil, 'perl'],
       [],
       ['python', nil, 'ruby']]

のようにすれば、空欄と空白行を入れ込むことができます。

(3) 省略型

 ExlBookオブジェクトを生成する時に、2次元配列やurl, html_string などを与えることができます。例えば、

   wb = ExlBook.new
   wb.push(ary)

の2行は

   wb = ExlBook.new(ary)

と書くことができます。生成時に引数を与えると、内部でpushが呼び出されます。

   ExlBook.new(ary).output_xml "test.xml"

のような記述も可能です。

(4) csvファイルの書き出し

 ExlBookクラスには output_csv(別名 csv_output)メソッドもあります。xmlssでなくcsvファイルを書き出すことができます。

   ExlBook.new(url).output_csv "test.csv"

のようにすれば、webのtableをcsv形式で書き出すことができます。

(5) webファイルの書き出し

 ExlBookクラスには output_web(別名 web_output)メソッドもあります。これによりwebファイルを書き出すことができます。

   wb = ExlBook.new
   wb.output_web('test.htm', 'test page')

のように用います。webページに付けるタイトルを第2引数として指定します。指定しない時は 'no title' になります。

 htmlに変換する際、セル結合以外の情報(font, alignment, bordersなど)は捨てます。色や文字の大きさなどは、webに反映されません。

 各々のワークシートが <table> …… </table> として出力されます。

 ワークシート名は、<table>の直前に <h2>……</h2> の形で出力されます。

-----------------------------------------------------------------------------

6. font(文字の大きさや色)の指定

 ExlBookクラスのpushメソッドに2次元配列を与える際に、fontの情報を埋め込むことができます。配列の各要素をHashにすることでその情報を埋め込みます。

(1) font情報の埋め込み

 font情報を埋め込むには、2次元配列の1つの要素を下のようにHashにします。

   {'Data'=>"ruby", 'Font'=>{'Size'=>"14"}}

 こうすると、セル内に表示される「ruby」の大きさが14ポイントになります(デフォルトでは11ポイント)。

 font情報には Size のほか Color、FontName(ゴシック、明朝等)の指定があります。

 Colorの値としては #000000 の黒(デフォルト)、#FFFFFF の白などを指定できます。BlueとかRedも指定可悩なようです。おそらくhtmlの色指定と同じ値を使えるのではないかと思います。

 FontNameの値には "MS Pゴシック" (デフォルト)や "MS 明朝" などが指定できます。

 デフォルト値を改めてHashで記述すると、下のようになります。

 {'Data'=>"ruby", 'Font'=>{
     'Color'=>"#000000",
     'FontName'=>"MS Pゴシック",
     'Size'=>"11"}}

(2) Hashの記述を簡単に済ますための eFont() および eData()

 上でfont情報の埋め込みについて書きましたが、Hash形式できちんと書くのは面倒です。

 そこで、簡易記述用メソッド eFont() および eData() を設けてあります。

 これらはクラスには属していません。module Exl に属しています。そのため、Exl::eFont() のように呼び出すか、あるいは、スクリプトの先頭の方で include Exl を書けば、「Exl::」を付けなくても呼び出せます。

(a) eFont()

 eFont() は、引数として color, font_name, size の3つを渡すことができます。この順番(頭文字 c, f, s のアルファベット順)で渡します。例えば

   eFont("Blue", "MS 明朝", "14")

というのは、

 {'Font'=>{'Color'=>"Blue", 'FontName'=>"MS 明朝", 'Size'=>"14"}}

と同じです。

 指定する必要のない項目は nil にします。そうすると、その項目はデフォルト値になります。

   eFont(nil, nil, "14")

とすれば、文字の大きさだけを変更する指定になります。

 Sizeの値は、文字列の形で "14" としても、数値の 14 としても、どちらでもOKです。以下に出てくる簡易記述用メソッドのいずれにおいても、数字の指定は同様です。

(b) eData()

 eData() は、データをHash形式に変換するのに用います。例えば、

   str = "ruby"
   p eData(str)  # => {'Data'=>"ruby"}

となりますが、引数としてHashが渡された時は、変換を施さずそのままを返します。

   hs = {'Data'=>"ruby"}
   p eData(hs)  # => {'Data'=>"ruby"}

 引数として nil を渡した時は、戻り値も nil になります。

 この eData() は、引数を複数指定できます。2番目以降の引数がHashであった場合、それらHashを第1引数に結合します。

   eData("ruby", eFont("Blue", nil, "14"))

という記述は、以下と同じです。

   {'Data'=>"ruby", 'Font'=>{'Color'=>"Blue", 'Size'=>"14"}}

 awk, perl, python, ruby が2×2の田の形で列んでいるとき、perlを青色、rubyを赤色にする例を掲げておきます。

   −−−− ここから
   #! ruby -Ks
     # coding: Shift_JIS
   require "exlap_c"
   include Exl
   ary = [%w(awk perl), %w(python ruby)]
   ary[0][1] = eData(ary[0][1], eFont("Blue"))
   ary[1][1] = eData(ary[1][1], eFont("Red"))
   wb = ExlBook.new
   wb.push(ary)
   wb.output_xml "test.xml"
   −−−− ここまで

(3) 構造体的Hash (structizeメソッド)

 当ライブラリをrequireしている場合、Hashを構造体的に記述することができます。

 構造体的というのは、例えば、hsがHashオブジェクトである場合、次のような記述ができることを意味します。

     hs.Data = "ruby"  # hs['Data'] = "ruby" と同等
     hs.Font.Color = "Red"  # hs['Font']['Color'] = "Red" と同等
     hs.Font.Size = 14  # hs['Font']['Size'] = 14 と同等

 ただし、Hashオブジェクトが総て上のように書けるというわけではありません。特化したHashに限ります。特化は次のように行います。

     hs = {}
     hs.structize

 このように、structizeメソッドを呼び出すと、その後、構造体的に記述できるようになります。この特化を行わなければ、通常のHashです。

 上の2行は、次の1行の形で書くこともできます。

     hs = {}.structize

 2次元配列の1つの要素を構造体的Hashにすれば、hs.Data とか hs.Font.Size などの記述が可能になります。

 先に上げた eData(), eFont() を用いたサンプルを、この方式で書き直してみると下のようになります。

   −−−− ここから
   #! ruby -Ks
     # coding: Shift_JIS
   require "exlap_c"
   ary = [%w(awk perl), %w(python ruby)]
   ary.map! {|row|
     row.map! {|data|
       cell = {}.structize
       cell.Data = data
       case data
       when "perl"
         cell.Font.Color = "Blue"
       when "ruby"
         cell.Font.Color = "Red"
       end
       data = cell
     }
   }
   wb = ExlBook.new
   wb.push(ary)
   wb.output_xml "test.xml"
   −−−− ここまで

 なお、既に構造体的Hashになっているオプジェクトhsに対して hs.structize を実行しても、何も実行されません。

 Hashオブジェクトの内部に「構造体化されているか否か」を記録するフラグがあり、それを参照した上でstructizeが実行されます。

(4) 構造体的Hashのmrgメソッド

 構造体的Hashには mrg というメソッドが用意されています。これは、別のHashを併合(merge)するためのものです。重複しない要素を残しつつ併合を行います。

 例えば、次の2つのHashがあるとします。

     hs1 = {}.structize
     hs1.Font.Color = "Blue"
     hs2 = {}.structize
     hs2.Font.Size = 14

 この場合の併合の結果は次のとおり。

     p hs1.mrg hs2  # -> {'Font'=>{'Color'=>"Blue", 'Size'=>14}}

 これに対し、updateで併合した時は次のとおりです。

     p hs1.update hs2  # -> {'Font'=>{'Size'=>14}}

 mrgの場合は Color と Size の両方とも残っているのに対し、updateの方は Size のみ残って Color が消えてしまいます。

 updateがHashの多重階層をチェックせずに単純に同じkeyのものを上書きするのに対し、mrgは、多重階層をチェックしつつ重複しないものを残す併合を行います。

 hs.Font.Size とか hs.Alignment.Horizontal のように、Hashの下に更にHashがくるような場合の併合に、このmrgメソッドが便利です。

[補足1] 簡易記述用メソッドが返す値は総て構造体的Hash

 前述の簡易記述用メソッド eData(), eFont() が返すHashは、いずれも構造体的Hashです。

 これ以降で紹介する簡易記述用メソッド eSpan(), eBorder() なども総て構造体的Hashを返します。

[補足2] 未定義の構造体的Hashが返す値は nil, {} の2通り

 hsが構造体的Hashである場合、hs.Data が未定義であれば nil を返します。hs['Data'] が nil になる仕様に即しています。

 しかし、hs.Font が未定義の時は、nil でなく {} を返します。Fontについては、hs.Font.Size のように、更にその下にHashがくると想定されるので、そのような仕様にしました。

 Fontの他に、Alignment, Borders, Interior, PhoneticText も同じく {} を返します。

[補足3] structizeが呼び出された時の内部処理

 当ライブラリの中で、ExlHashStruct という module が定義されています。

 そして、{}.structize のようにHashを構造体化すると、そのExlHashStructモジュールがHashオブジェクトにextendされます。これで「構造体化」が実現されます。

-----------------------------------------------------------------------------

7. Hash形式で埋め込む情報あれこれ

 2次元配列の要素をHashにすることによって、font情報以外にも埋め込むことのできる情報があります。

(1) セル結合 eSpan()

 セル結合を示す時は、配列の1つの要素を例えば次のようにします。

   {'Data'=>"セルA1", 'Cspan'=>2, 'Rspan'=>2}

 上は、データが「セルA1」であって、右隣のセルと下隣のセルを結合する指定になります。

 cspanが横方向の結合、rspanが縦方向の結合です。

 cspan, rspan が1であれば、その方向での結合はなしという意味になります。2以上が結合を意味します。

 cspan, rspan を常に2つとも指定しなければならないわけではありません。横方向だけの結合なら cspan だけ指定すればOKです。

 結合範囲は、左上端以外は空欄(nil)になっていないと、トラブルの原因になるので注意して下さい。つまり、結合される側のセルは、空欄(nil)でなければなりません。

 セル結合についても簡易記述用メソッド eSpan() 別名 eMerge() があります。引数は2つで、cspan, rspan の順に渡します。

 eSpan(2) だと、横方向2個分の結合、eSpan(nil,3) だと、縦方向3個分の結合の指定になります。

 セル結合用の2次元配列の例を下に掲げておきます。

   ary = [
       [eData("セルA1", eSpan(2,2)), nil, "セルC1"],
       [],
       ["セルA3", nil, "セルC3"]]

(2) 罫線 eBorder()

 罫線は、セルの上・下・左・右の各々について指定する必要があります。これをHashで記述すると、例えば、次のようになります。

 {'Borders'=>{
   'Border1'=>{"Position"=>"Top",
     "Weight"=>"1",
     "LineStyle"=>"Continuous"},
   'Border2'=>{"Position"=>"Bottom",
     "Weight"=>"1",
     "LineStyle"=>"Continuous"},
   'Border3'=>{"Position"=>"Left",
     "Weight"=>"1",
     "LineStyle"=>"Continuous"},
   'Border4'=>{"Position"=>"Right",
     "Weight"=>"1",
     "LineStyle"=>"Continuous"}}}

 上の "Weight" は罫線の太さ、"LineStyle" は罫線の種類(実線か点線かなど)です。

 各々どのような値を取り得るのかちゃんと把握してませんが、Weightが1だと細線、LineStyleがContinuousだと実線になるようです。

 簡易記述用メソッド eBorder() 別名 eBox() を設けてあります。

 引数は3つで、LineStyle, Weight それから Color の順で指定します。Colorは、Fontの時と同じ値を指定できます。

 eBorder("Dot") とすれば、実線でなく点線を指定することになります。

 引数として nil を与えた場合(あるいは省略した場合)、LineStyle なら "Continuous" が、 Weight なら 1 が指定されたものとみなされます。Colorは無指定がデフォルトです。

 引数を何も指定せずに eBorder() とすれば、eBorder("Continuous", 1) と同じです。

 以下に、総ての空欄でないセルを細い実線で囲む例を示してみます。

   −−−− ここから
   #! ruby -Ks
     # coding: Shift_JIS
   require "exlap_c"
   include Exl
   ary = [%w(awk perl), %w(python ruby)]
   ary.map! {|row|
     row.map! {|col|
       col = eData(col, eBorder())
     }
   }
   wb = ExlBook.new
   wb.push(ary)
   wb.output_xml "test.xml"
   −−−− ここまで

 eBorder の他に、eBorder_t, eBorder_b, eBorder_l, eBorder_r の4つの簡易記述用メソッドもあります。いずれも引数は eBorder と同じです。

 eBorder_t はセルの上辺(top)、eBorder_b は底辺(bottom)、eBorder_l は左辺(left)、eBorder_r は右辺(right)の罫線を引くものです。一定の領域の外枠罫線を引くような時に用います。

 例えば、2×2の領域の外枠罫線を引く例は下のとおり。

   −−−− ここから
   #! ruby -Ks
     # coding: Shift_JIS
   require "exlap_c"
   include Exl
   ary = [%w(awk perl), %w(python ruby)]
   max_y = ary.size-1
   for y in 0..max_y
     max_x = ary[y].size-1
     for x in 0..max_x
       cell = {}.structize
       cell.Data = ary[y][x]
       cell.mrg eBorder_t()  if y == 0
       cell.mrg eBorder_b()  if y == max_y
       cell.mrg eBorder_l()  if x == 0
       cell.mrg eBorder_r()  if x == max_x
       ary[y][x] = cell
     end
   end
   wb = ExlBook.new
   wb.push(ary)
   wb.output_xml "test.xml"
   −−−− ここまで

(3) 文字の配置 eAlignment()

 文字のセル内での配置位置を指定するには alignment を用います。Hashで記述すると、例えば、次のようになります。

   {'Alignment'=>{'Horizontal'=>"Left",
       'Vertical'=>"Center", 'WrapText'=>"1"}}

 Horizontalが水平方向(横方向)の位置で、Left, Center, Right などの値を採ります。デフォルトは無指定。

 Verticalが垂直方向(縦方向)の位置で、Top, Center, Bottom などの値を取ります。デフォルトは Center。

 WrapTextは、長い行の折り畳みを行うか否かの指定で、1 なら折り畳みがonになります。デフォルトは無指定。

 行の折り畳みは、セルの幅と高さが的確に設定されていないと意味がありません。幅と高さの設定については後述します。

 簡易記述用メソッド eAlignment() があります。

 引数は3つで、Horizontal, Vertical, WrapText の順に指定します。

   eAlignment("Left", "Top", "1")

のように指定します。

 以下にサンプルを掲げます。3×3のセル欠合領域にデータ1つづつを入れ、その配置位置を変えている例です。

   −−−− ここから
   #! ruby -Ks
     # coding: Shift_JIS
   require "exlap_c"
   include Exl
   ary = [
       ['awk', nil, nil, 'perl', nil, nil],
       [],
       [],
       ['python', nil, nil, 'ruby', nil, nil],
       [],
       []]
   ary.map! {|row|
     row.map! {|col|
       params = []  # eAlignment() に渡す引数
       case col
       when 'awk'
         params = %w(Left Top)
       when 'perl'
         params = %w(Center Center)
       when 'python'
         params = %w(Left Bottom)
       when 'ruby'
         params = %w(Right Bottom)
       end
       col = eData(col, eSpan(3,3), eAlignment(*params))
     }
   }
   wb = ExlBook.new
   wb.push(ary)
   wb.output_xml "test.xml"
   −−−− ここまで

(4) 背景色 eInterior()

 セルの背景色の指定は interior で行います。例えば、Hashで次のように書くと、背景が黒に切り替わります。

   {'Interior'=>{'Color'=>"#000000", 'Pattern'=>"Solid"}}

 色の値は、font情報の場合と同じです。

 Patternの方は、よく分かりませんが、"Solid" にしないと、色の変更がちゃんと反映されない?と思います。

 簡易記述用メソッド eInterior() は、引数が2つです。Color, Pattern の順に渡します。

 色だけ指定した場合は、Patternが自動的に "Solid" になります。

   ary[0][0] = eData("ruby", eFont("#FFFFFF"), eInterior("#000000"))

とすれば、A1欄が白黒反転、つまり背景が黒、文字が白になります。

(5) 計算式、関数 eFormula()

 計算式や関数をセルに書き込みたい時は、Hashの 'Formula' 要素で指定します。

 式や関数の中でのセル番地は、A1とかB2などでなく、RC方式で書きます。

 Hash の 'Data' 要素の値は、計算式や関数で算出されるのと同じデータ型のもの(内容は適当でかまわない)を書いておきます。文字型になるはずなら "xyz" などとしておきます。整数が算出されるはずなら0とか1、小数点数なら0.0、10万分の1のような微小な小数点数なら 3.14e-05 など適当な数値を書いておきます。

 例えば、次のように書きます。合計を求めるSUM関数、アルファベットを小文字に変換するLOWER関数の例です。

   ary = [
     [5, 6, 7, {'Data'=>1, 'Formula'=>"=SUM(RC[-3]:RC[-1])"}],
     ["ABC", {'Data'=>"xyz", 'Formula'=>"=LOWER(RC[-1])"}]]

 簡易記述用メソッド eFormula() は、引数は1つだけです。計算式や関数を文字列で渡します。

 上記の Hash 形式を次のように書くことができます。

   ary = [
     [5, 6, 7, eData(1, eFormula("=SUM(RC[-3]:RC[-1])"))],
     ["ABC", eData("xyz", eFormula("=LOWER(RC[-1])"))]]

 セルに計算式や関数が埋め込まれている場合、csv|web出力時に、xmlssに書き込まれているデータ(不正確な可能性あり)に加えて、Formulaの式を出力するようにしました。ただし、そのFormulaの式に対応するrubyスクリプトが定義されている場合(下の[参考]参照)、または変数$ExlapFormulaOutがnilかfalseの場合は出力しません。ちなみに、$ExlapFormulaOutのデフォルト値はnil。

 例えば、関数が埋め込まれているセルをcsvに出力した場合、「123 |=SUM(RC[-3]:RC[-1])」のように出力されます。

 123は、xmlssに書き込まれていた値です(不正確かもしれません)。それに続いて半角スペースと'|'、そして '=SUM……' の関数記述が続きます。

[参考] Formulaの式に対応するrubyスクリプトの定義

 セルにFormulaの式が埋め込まれていると、Excelで開いた時はちゃんと計算結果が表示されますが、exlap_cライブラリでcsvやwebに変換した場合は、先述したように、とりあえずの値と式を出力します。

 ただし、その式の代替となるrubyスクリプトが定義されている時は、それに従って計算結果を出力します。式そのものの出力はしなくなります。

 この定義は、グローバル変数 $formula(Hash)で行います。$formulaは、exlap_cライブラリをrequireした時に空のHashとして定義されます(既にHashとして定義されていれば空にしない)。

 $formulaのkeyにはExcel用の式、valueにはrubyスクリプトを記録します。

 例えば、左隣のセルのアルファベット大文字を小文字に変換する例は次のとおり。

   key = "=LOWER(RC[-1])"
   val = "data = getData(aa[rn][cn-1]).to_s.tr('A-Z', 'a-z')"
   $formula[key] = val

 代替のrubyスクリプトにおいて、次の変数は特別の意味を持ちます。

  • aa: 2次元配列
  • rn: 現在の行番号(0以上)
  • cn: 現在の列番号(0以上)
  • data: セルに代入する値をこの変数に入れる。
  • fr_scriptなど: 「fr_」で始まる変数名は、用いないで下さい。

 上記以外のローカル変数は、自由に名前を付けて用いることができます。

 代替のrubyスクリプトにおける漢字コードは、2次元配列のコードと同じになるよう調整されます。スクリプトを書く時に漢字コードを気にする必要はありません。

 なお、先の例に出てくるgetData(param)は、paramがHashならparam['Data']を返し、そうでないならparamそのものを返します。このメソッドは、eData() や eFont() などと同様、Exlモジュールの中で定義されています。

(6) データ型

 exlap_cでは、データ型を自動判別します(Excelに似ていますが、違う点もあります)。

 例えば、「50%」は、数値型の 0.5 となります(表示は「50%」のままです)。

 しかし、これをあえて文字型にしたい場合は、Hashの'Type'要素に'String'を指定します。次のような形です。

   {'Data'=>"50%", 'Type'=>"String"}

 データ型には String Number DateTime がありますが、数値として扱えないものをNumberに指定しようとするとトラブルの原因になります。データ型を指定する場合は、実質的に「Stringを指定するか否か」の判断に限定するのが無難です。

 なお、「001」は数値の1となりますが、表示は「001」を保ちます。あえてStringを指定しなくても大丈夫です。

 また、「3.0」のように小数点以下が0であっても、省略されず「3.0」と表示されます(値は数値の 3 です)。

 簡易記述用メソッドの eType() は、引数が1つだけです。"String" などのデータ型を文字列で渡します。

   ary = [
       [eData("50%", eType("String")), "50%"],
       [eData("001", eType("String")), "001"],
       [eData("3.0", eType("String")), "3.0"]]

 それから、セルの一部分のみを赤色にしたり下線付きにしたりする場合は、データ型を 'String@html' として、データ本体はhtml形式で記述します。

 例えば「あいうえおかきくけこ」のうち「あいうえお」だけを赤色にしたい場合、2次元配列の1つの要素を次のようにセットします。

   ary[0][0] = eData(
       '<Font html:Color="Red">あいうえお</Font><Font>かきくけこ</Font>',
       eType('String@html'))

 データ型として 'String@html' のように '@html' を付加すると、そのデータはhtml形式で記述されているものとして処理されます。

 html形式といっても、一般的なhtml記述のルールとは異なるような気がしますが、正確な仕様は分かりません。

 <I>……</I>でイタリック、Bなら太字、Uなら下線、といったタグが使えるようです。

 誤って記述すると、Excelで読み込みのできないxmlssになってしまうので注意して下さい。

 通常のデータは、xmlssにおいて <Data ss:Type="String">……</Data> などのようになりますが、Typeに 'String@html' を指定した場合は、<ss:Data ss:Type="String">……</ss:Data> に変換されます。

 このhtml形式の場合、当然ながら、'<' を '&lt;' に変換するといった処理は施しません。それ以外の通常のデータについては、exlap_cライブラリがその種の変換を施します。

(7) 数値型の表示形式

 Excelでは、数値型の表示形式をNumberFormatLocal で指定します。例えば、1を「001」にしたい時は NumberFormatLocalを "000" にします。

 3桁ごとにカンマ区切りを入れたいなら "#,##0" のような形です。

 exlap_cライブラリでのこの指定は、Hashの 'NumberFormat' 要素で行います。次のような形です。

   {'Data'=>"1234", 'NumberFormat'=>"#,##0"}

 ただし、わざわざHashを使わなくても、単に "1,234" のデータを与えれば、表示形式が自動判別されて "#,##0" になります。

 このようなexlap_cの自動的処理で対応できない時に、number_format を指定するということでいいと思います。

 簡易記述用メソッド eNumberFormat() は、引数が1つだけです。表示形式を示す文字列 "000" とか "#,##0" などを渡します。

 以下に、数値を総て小数点2桁まで表示するように統一する例を掲げます。

   −−−− ここから
   #! ruby -Ks
     # coding: Shift_JIS
   require "exlap_c"
   include Exl
   ary = [
       [56, 12.4, 35.42],
       [234.8, 94, 39.1]]
   ary.map! {|row|
     row.map! {|col|
       col = eData(col, eNumberFormat("##0.00"))
     }
   }
   wb = ExlBook.new
   wb.push(ary)
   wb.output_xml "test.xml"
   −−−− ここまで

(8) 日付・時刻型

 Excelでは、日付・時刻型(DateTime)のデータは、数値型(Number)と同じく、表示形式を NumberFormatLocal で設定します。なので、eNumberFormat() で設定できるわけですが、正直なところ、どのように指定できるのかちゃんと把握してません。

 ここでは、とりあえず、exlap_cが日付・時刻型として自動判別するケースについて記しておきます。

 DateTimeとして自動判別するのは次のパターンです。

   2010/10/09
   2010-10-09
   2010年10月9日
   平成22年10月9日

(西暦の年が2桁のもの、あるいは、年が省略されているもの("10/09" とか "10月9日")は、日付型として判別せず String とみなします。)

 また、次のパターンを時刻として判別します。

   11:32
   15:18:44

 日付と時刻の組合せ、例えば "2010/10/09 15:32" のような形は、DateTimeとして自動判別しないので注意して下さい。Stringとみなされます。

 以上のような自動判別で満足できない場合は、eNumberFormat() などで表示形式を設定してみて下さい。

-----------------------------------------------------------------------------

8. ワークシートを記録するための ExlSheet クラス

 ワークシートには、シート名など2次元配列には記録できない情報がいくつかあります。

 例えば、セルの幅と高さもその1つです。個々のセルについて高さと幅をばらばらに設定したのでは表の形式が崩れてしまうので、セルの情報としてでなく別枠でその情報を保持します。

 exlap_cでは、ワークシートを記録するためのクラス ExlSheet を設け、その一部にワークシート名などを記録するようにしています。

 以下、そのクラスについて記します。

 なお、以降では ExlSheetオブジェクトをssという2文字の変数で表現しています。

(1) ExlSheetで記録・保持される情報(メンバー変数)

 ExlSheetクラスでは次の情報が記録・保持されます。

  • 2次元配列 @array (デフォルトは nil)
  • ワークシート名 @name (デフォルトは nil)
     nilの場合、xmlss出力に際して Sheet1 などの名前が割り当てられる。
     シート名として ':', '*', '?', '', '[', ']' の文字を使えないので注意。
  • 始点 @start_rc (デフォルトは nil)
     これが nil または [0,0] だと、左上端(A1)がシート内の始点になります。
     [1,1] なら、B2 が始点になります。1行目を空けたいなら [1,0] です。
     [y,x] (y>=0, x>=0)の形で指定します。
  • 表の情報(表に共通するfontなど) @tbl (Hash形式)
  • 行の情報(高さなど) @row (行数分の配列)
  • 列の情報(幅など) @col (列数分の配列)
  • データの出所タイプ @source_type (:WEB | :CSV | :XMLSS)
  • データ取得の手がかり @source_clue
     url | html_string | csv_filename | csv_string のどれかがこれに記録される。
     2次元配列がデータの出所である時は nil
  • 対応外のエレメント情報 @other(Hash) (デフォルトは {})
     これについては ver 1.2.2→1.2.3のバージョンアップ履歴を参照。

 上の情報には、いずれも次のようにして値を代入できます。

   ss = ExlSheet.new
   ss.array = ary
   ss.name = "Sheet1"
   ss.start_rc = [1,0]
   ss.tbl = eFont("Green")
   ss.row = [eHeight(2), nil, nil, eHeight(3)]
   ss.col = [eWidth(32), nil, eWidth(14)]
   ss.source_type = :WEB
   ss.source_clue = 'http://www.hogehoge.com/'

 また、最初の3つは ExlSheet 生成時に引数として渡すことができます。例えば

   ss = ExlSheet.new(ary, "test sheet", [1,0])

 参照も代入と同じように行えます。

 2次元配列の ss.array については次のように参照することができます。

   val = ss[0,0]  # val = ss.array[0][0] と概ね同じ
   ss[1,1] = val  # 代入も可能
   sheet_name = ss.name
   stype = ss.source_type

[補足] 2次元配列の1つの要素(セル)の扱い方

 2次元配列 ss.array は、初期値がnilです。そのため、いきなり ss.array[1][1] のように参照すると、エラーが発生します。代入しようとする時も同様です。

 しかし、ss[y,x] の形式で呼び出した場合はエラーが起きません。

 「val = ss[1,1]」のような参照呼び出しの時は、ss.arrayのサイズを超えるものについて、nilを返します。

 「ss[1,1] = val」のような代入呼び出しの時は、ss.arrayのサイズを必要なだけ拡張した上で代入を行います。

 という仕様なので、2次元配列の1つの要素(セル)を扱う場合、ss.arrayで直接扱うより、ss[y,x]の形式を使う方が便利です。

 それから、ss.cell(y,x) という形式もあります。この cell() は、返り値が常に構造体的Hashです。

 ss.cell(1,1) が呼び出されると、該当セルが構造体的Hashに変換され、それが戻り値として返されます。

 該当セルが nil の時は {} に変換されます。通常のHashではなく構造体的Hashです。

 該当セルが "abc" であったとすれば、{'Data'=>"abc"} に変換されて、それが返されます。

     ss.cell(1,1).Data = "ruby"
     ss.cell(1,1).Font.Color = "Red"

とすれば、B2欄に "ruby" という文字列がセットされ、その色が赤に設定されます。

     cell = ss.cell(1,1)
     cell.Data = "ruby"
     cell.Font.Color = "Red"

と書いても同じ結果になります。

 ただし、この cell() は、下のような代入の形では使えないので注意して下さい。

     ss.cell(0,0) = {'Data'=>"abc"}
     ss.cell(0,1) = "abc"

(2) ExlBookクラスとの関係

 これまで掲げたサンプルでは ExlBook クラスが用いられていました。このクラスは、内部処理において ExlSheet を扱っています。

   wb = ExlBook.new
   wb.push(url)

とすると、webから取得したtable(複数ある可能性あり)をExlSheetで記録します。それらは当該クラスの @sheets に記録されます。なので、ExlBookのワークシート情報には次のようにしてアクセスできます。

   wb = ExlBook.new
   wb.push('http://www.hogehoge.com/')
   wb.sheets.each {|ss|
     p ss.source_type  # => :WEB
     p ss.source_clue  # => "http://www.hogehoge.com/"
     p ss[0,0]  # => "Hello, hogehoge"
   }

 ExlBookクラスについては、後でもう少し詳しく記しますが、各ワークシートが ExlSheet で保持されている点を覚えておいて下さい。

 また、ExlBookのpush()メソッドには、引数としてExlSheetオブジェクトを渡すことができます。

(3) 行の高さなどの指定

 行の高さは、ss.row (配列)に適当な値をセットして設定します。

 基本的には行数分のデータをセットしますが、ss.row[i] が nil の時はデフォルト値が用いられます。

 デフォルト値は {'Height'=>"13.5"} です。行の高さがデフォルトで13.5ポイントになっています。

 2行分の高さにしたい時は 13.5*2 の 27.0 にします。

 数値をセットするのでなく {'Height'=>"27.0"} のようにHash形式でセットします。

 これだと面倒なので、簡易記述メソッド eHeight() を設けてあります。eHeight(2) とすれば、2行分の高さになります。

   ss.row = [eHeight(2), nil, eHeight(3)]

とした場合は、1行目の高さが2行分、2行目はデフォルトの1行分、3行目が3行分となります。

 ss.row の初期値は [] の空配列です。つまり、どの行もデフォルトの1行分の高さとなります。

 ss.rowを設定する場合、そのワークシートには最大何行あるのかを知る必要が出てきますが、それは ss.max_row() で知ることができます。

   for i in 0...ss.max_row()
     ss.row[i] = ……
   end

とすれば、1行分ごとに行の高さをセットできます。

 なお、ss.rowには行の高さの他に、その行全体に適用するfontなどをセットしておくこともできます。第1行目を総て青色にするなら

   ss.row[0] = eFont("Blue")

とします。

 第1行目についてその高さを2行分、色を赤にする場合なら、Hashの結合・更新メソッド update を用いて

   ss.row[0] = eHeight(2).update(eFont("Red"))

とします。

(4) 列の幅などの指定

 列の幅は、ss.col (配列)に適当な値をセットして設定します。

 基本的には列数分のデータをセットしますが、ss.col[i] が nil の時はデフォルト値が用いられます。

 デフォルト値は {'Width'=>"54"} です。この54は、ピクセル数だと思いますが、詳しいことは分かりません。おおよそ半角8文字強が入る幅だと思います。

 私の経験でいうと、Widthの値を半角文字数×6.5に設定しておけば、ちょっと余裕のある幅に設定できます。

 そこで、簡易記述メソッド eWidth() では、引数として半角文字数を渡すと、その6.5倍の値がセットされるようにしてあります。

 eWidth(10) は、{'Width'=>"65"} と同じです。

 微妙な値をセットしたい時は、Hash形式で指定して下さい。

   ss.col = [eWidth(32), nil, eWidth(10)]

とした場合は、1列目の幅が32桁分、2列目はデフォルト、3列目が10桁分となります。

 ss.col の初期値は [] の空配列です。つまり、どの行もデフォルトの8桁強分の幅となります。

 ss.colを設定する場合、そのワークシートには最大何列あるのかを知る必要が出てきますが、それは ss.max_col() で知ることができます。

   for i in 0...ss.max_col()
     ss.col[i] = ……
   end

とすれば、1列分ごとに列幅をセットできます。

 なお、ss.colには列の幅の他に、その列全体に適用するfontなどをセットしておくこともできます。第1列目を総て青色、第2列目を総て茶色にするなら

   ss.col[0] = eFont("Blue")
   ss.col[1] = eFont("Brown")

とします。

(5) 各列の最大幅を求める mloc()

 列の幅を設定する場合、2次元配列における各々の列の幅の最大値が分かれば便利です。

 そこで、それを調べるためのメソッド mloc() を設けてあります。これは省略名で、ほんとは max_length_of_col() です。

 このメソッドは、配列を返します。配列には各列の最大幅(桁数)が記録されます。

 ここでいう桁数は、半角を1、全角を2とする値です。

 1つのタブコードは、4桁として数えます。これを変更したい時は、グローバル変数 $ExlapTabLen の値を 2 とか 8 など別の数値にして下さい。

   mc = ss.mloc()
   mc.each {|len|
     p len
   }

とすれば、各々の列の最大幅を出力できます。

 この最大幅を求める際、次の特徴があります。

  • 横方向にセル結合されている場合は、結合セル数で割って平均値を1つのセルの幅とみなします。
     例えば、A1に60桁のデータがあり、それがB1, C1の2つをセル結合しているとすると、その幅は60桁でなく、60/3=20桁とみなします。
  • 複数行からなるデータの場合、つまり改行コードを含むデータの場合は、改行コードで分割し、最も長い行によってその幅を求めます。

 mloc() には2つの引数を渡すことができます。何行目から何行目までを調査対象にするかを指定できます。

 何行目かを示す数値は、0から始まります。1ではないので注意して下さい。

   mc = ss.mloc(1,5)

とすれば、第2行目から第6行目までを調べるとの指定になります。

 1番目の引数をnilにすれば(あるいは省略すれば)、0が指定されたものとみなされます。第1行目から調べます。

 2番目の引数を省略すれば、最後の行までを調査対象とします。

 第1行目がcaptionで、例外的に長いような場合、ss.mloc(1) とすれば、第2行目以降について調べることができます。

* 残念ながら、各々の行について最大行数を求める mlor() は設けていません。試みましたが、ちょっと面倒でやめました(あせ)。

 列の幅と行の高さを調整するサンプルを示してみます。関東地区のテレビ番組視聴率のサイトをxmlssにするものです。

 表の第1行目は、タイトルなので特に調整は行いません。

 第2行目は、項目名を列記したものですが、これは高さを2行分にします。

 3行目以降について、列幅が40桁を超えるものがある時は40桁に調整します。そして、3行目以降の行の高さを総て2行分にします。

 40桁を超えるものがなければ、列幅のみ調整し、行の高さは1行分のままとします。

   −−−− ここから
   #! ruby -Ks
     # (coding: Shift_JIS)
   require "exlap_c"
   include Exl
   url = 'http://www.videor.co.jp/data/ratedata/top10.htm'
   wb = ExlBook.new
   wb.push(url)
   wb.sheets.map! {|ss|
     mc = ss.mloc
     p mc
     over_flag = false
     for i in 0...mc.size
       if mc[i] > 40
         mc[i] = 40
         over_flag = true
       end
       ss.col[i] = eWidth(mc[i])
     end
     ss.row[1] = eHeight(2)  # 第2行目は必ず2行分の高さ
     if over_flag  # 桁数オーバーのものがあった
       for i in 2...ss.max_row  # 3行目以降の高さを2行分に
         ss.row[i] = eHeight(2)
       end
     end
     ss.array_update(eAlignment(nil, nil, 1))
   }
   wb.output_xml "videor02.xml"
   −−−− ここまで

 上に出てくる ss.array_update については、すぐ下の項目を参照して下さい。

(6) 各要素に一律にHashを付加する array_update()

 2次元配列 ss.array の空欄でない全要素について、一律に同じ情報(例えば、罫線を引くための情報など)を付加したいことがあります。

 そんな時に ss.array_update() が使えます。

   ss.array_update(eBorder())

とすれば、空欄でない全欄に罫線を引くことになります。ここでいう空欄とは、値がnilの2次元配列の要素のことです。

   ss.array_update(eAlignment(nil, nil, 1))

とすれば、空欄以外の総ての欄を「行の折り畳みon」に設定します。

 このメソッドに渡す引数は、必ずHashにします。

   ss.array_update({'Font'=>{'Size'=>"14"}})

のような形です。

 渡された引数は、各要素に結合されます。構造体的Hashの結合(mrgメソッド)を各欄に実行します。

 戻り値は self です。

(7) 各要素に一律に変換を施す array_convert()

 ss.array (2次元配列)の空欄でない総てのセルに対し、一律に変換を施したいとき、この array_convert() を用います。

 簡単な変換用スクリプト(文字列)を引数として渡すと、それが各セルについて eval で実行されます。

 各セルのデータは、文字列型(String)で str という変数に入っています。行番号は rn、列番号は cn(どちらも0以上の整数型)です。

 例えば、Yahooテレビ番組表では「▽」や「◇」を改行にしてしまうと読みやすくなったりしますが(?)、それを行うには次のようにします。

     scr = 'str = str.gsub(/(▽|◇)/, "\n")'
     ss.array_convert(scr)

 スクリプト scr の漢字コードは、適宜調整されます。

 セル内で空白行(改行コードだけの行)を取り除きたいなら次のようにします。

     scr = 'str = str.gsub(/\n\n+/, "\n")'
     ss.array_convert(scr)

 scrには複数行にわたるスクリプトを代入しても、もちろんOKです。

 戻り値は self です。

(8) ワークシートが空か否かを返す empty?()

 ss.empty?() が true であれば、ワークシート ss は空です。

 ss.array が nil または [] あるいは [[]] のどれかであることを意味します。

(9) ワークシートを全消去する clear()

 ss.clear() を実行すると、ワークシートが空になります。ss.array が nil になります。

(10) 部分的領域(range)を返す range()

 まだ言及していませんが、ワークシート内の部分的領域を扱うための ExlRange クラスがあります。

   rng = ss.range(0,0, 2,2)

とすれば、A1欄からC3欄にかけての3×3の領域が変数rngにセットされます。rngをどのように扱えるかについては後述します。

   rng = ss.range(1,1)

とすれば、B2欄1つのみがrngにセットされます。

(11) ワークシート全体をrangeとして返す entire_range()

 左上端のセル(A1欄)から終端セルまでの領域、つまりワークシート全体をrangeとして返すのが entire_range() です。

 ワークシートが空の時は false を返します。それ以外の時は ExlRangeオブジェクトを返します。

 ワークシートがセル結合を含む場合、ss.array のサイズよりも大きい領域を返すことがあるので留意して下さい。

 例えば、ワークシートの左上端セル1つにしかデータが書き込まれていないとすれば、

   rng = ss.entire_range()

として得られたrngにはセルが1つしか含まれません。

 しかし、そのセルが2×2の領域を結合していれば、rngの領域は、2×2の4つのセルを含むrangeになります。

(12) 使われている領域全体を返す used_range()

 このメソッドは、entire_range() と類似していますが、始点が必ずしもA1欄でない点が異なります。

 例えば、ワークシートの1行目が空白行で、2行目の左端セルから始まっているとすれば、A2欄からワークシートの終端までのrangeを返します。

 ワークシートが空の時は false を返します。それ以外は ExlRangeオブジェクトを返します。

 ワークシートがセル結合を含む場合、ss.array のサイズよりも大きい領域を返すことがあります。

(13) 指定した1行をrangeとして返す row_range(y)

 引数yで指定した行をrangeとして返します。例えば、

   rng = ss.row_range(0)

とすれば、第1行目がrangeとして返されます。

 該当の行が空白行の場合等、領域を確保できない時は false を返します。それ以外は ExlRangeオブジェクトを返します。

(14) 指定した1列をrangeとして返す col_range(x)

 引数xで指定した列をrangeとして返します。例えば、

   rng = ss.col_range(0)

とすれば、第1列目がrangeとして返されます。

 該当の列が空白行の場合等、領域を確保できない時は false を返します。それ以外は ExlRangeオブジェクトを返します。

(15) 他のワークシートかrangeのコピーを生成する copy_from()

 copy_from() は、別のワークシートまたはrangeのコピーを生成し、そのコピー領域をrangeとして返します。

   rng = ss.copy_from(other)

とすれば、otherの内容全部をコピーして、その結果をrangeとして返します。ssの左上端(A1欄)を始点とするrangeになります。

 otherは、別のワークシートを示すExlSheetオブジェクトか、またはExlRangeオブジェクトでなければなりません。その条件に合致しない場合、copy_from() は false を返します。

 コピーの始点をA1欄でなく別の位置にしたい時は

   rng = ss.copy_from(1,1, other)

などのようにします。こうすると、B2欄を始点とする領域にコピーが生成され、その結果が返されます。

(16) セル結合範囲の両端の番地を返す merge_address(y,x)

 例えば、A1欄に2×2の領域が結合されているとします。つまり、A1:B2 がセル結合されている状態です。この場合、

   addr = ss.merge_address(1,1)

とすれば、addr は [0,0, 1,1] となります。セル結合範囲の両端の番地が戻り値として返されるわけです。

   addr = ss.merge_address(0,1)
   addr = ss.merge_address(1,0)

のいずれも同じ戻り値になります。

 引数として渡された y,x がセル結合範囲に属していない時は nil を返します。

(17) セル結合範囲をrangeとして返す merge_area(y,x)

 引数として与えられた番地(y,x)を含むセル結合範囲を、rangeとして返します。

 例えば、A1欄に2×2の領域が結合されているとします。A1:B2 がセル結合されている状態です。この場合、

   rng = ss.merge_area(0,1)

とすれば、A1:B2 の2×2の領域がrngにセットされます。

 引数として渡された y,x がセル結合範囲に属していない時は false を返します。

-----------------------------------------------------------------------------

9. ワークシート内の一定領域を記録するための ExlRange クラス

 ワークシート内の一定領域を記録し、それに処理を施すための ExlRange クラスがあります。例えば、

   rng = ss.range(0,0, 1,1)

とすれば、A1:B2 の2×2の領域が変数rngにセットされますが、このrngは、ExlRangeオブジェクトです。

 この領域内の1つのセルは、rng[0,0] とか rng.cell(1,1) のようにして参照できます。領域の左上端が 0,0 です。

 あるいは、rng.each {|cell| …… } といった記述も可能です。

 以下、ExlRangeクラスについて記しますが、変数rngは、ExlRangeオブジェクトを示すものとします。

(1) ExlRangeで記録・保持される情報(メンバー変数)

 ExlRangeには次の5つのメンバー変数があります。いずれも外部から読み書き可能です。初期値は nil です。

  • @sheet: 領域が属するワークシート(ExlSheetオブジェクト)
  • @sy: 領域の始点のy座標値(0以上の整数) start y のつもり。
  • @sx: 領域の始点のx座標値(0以上の整数) start x のつもり。
  • @ly: 領域の終点のy座標値(0以上の整数) last y のつもり。
  • @lx: 領域の終点のx座標値(0以上の整数) last x のつもり。

 新たにオブジェクトを生成する時は

   rng = ExlRange.new(ss, 0,0, 2,2)

あるいは

   rng = ss.range(0,0, 2,2)

のようにします。この場合、A1:C3 の3×3の領域がrngにセットされます。

   rng = ExlRange.new(ss, 1,1)

のように、始点だけ与えて終点を指定しない時は、1つのセルのみから構成される領域がセットされます。

 オブジェクトの生成に失敗した場合は、その旨のエラーメッセージを出力します。@sheetなどのメンバー変数の値は、nilのままです。

 以下、ExlRangeクラスのメソッドについて記します。

(2) 1つのセルを参照する rng[y,x]

 rngがExlRangeオブジェクトであるとき、rng[0,0] は、領域の左上端のセルを示します。

   rng = ExlRange(ss, 1,1, 2,2)

とすれば、rngが B2:C3 の2×2の領域となりますが、この時に rng[0,0] は、領域の左上端を示します。つまり ss[1,1] (B2欄)を示します。rng[1,1] は、ss[2,2] です。

 rng[y,x] は、参照も代入も両方とも可能です。

   val = rng[0,1]
   rng[1,0] = val

のような記述が可能です。

 引数 y,x が領域の範囲外である場合は、rng[y,x] は false を返します。また、

   rng[y,x] = val

としても代入は行われず false を返します。ちなみに、y,xが範囲内であれば戻り値は rng[y,x] つまり val です。

(3) 1つのセルを構造体的Hashで参照する rng.cell(y,x)

 rng.cell(0,0) は、領域の左上端のセルを示しますが、値として構造体的Hashを返します。

 なお、引数 y,x が領域の範囲外である場合は false を返します。

(4) データの参照と代入 rng.Data

 領域内の各セルのデータを一括して配列の形で取得したい時は、

   ary = rng.Data

のようにします。こうすると、aryに2次元配列がセットされます。その要素は、各セルのData値です。

 例えば、rngが A1:B2 の2×2の領域を示しており、1行目は awk, perl、2行目が python, ruby が書かれているとします。この場合、

   ary = rng.Data

として得られる ary は、"awk", "perl"], ["python", "ruby" です。

 領域内に何もデータが書かれていない時は、空配列 [] を返します。

 一方、「rng.Data = ary」の形で、データの一括代入を行うことができます。

 この場合、右辺のaryが2次元配列であれば、その行と列の位置関係が維持される形で代入が行われます。aryの1行目がrngの1行目に、2行目は2行目に代入されます。rngとaryの行数または列数が異なる時は、それぞれ小さい方に合わせます。

 aryが1次元配列の時は、そこから1つづつ要素を取り出して、領域内のセルにセットしていきます。配列の要素がなくなれば、そこで処理を終了します。

 領域内の総てのセルにデータをセットして、それでも配列の要素が余っていれば、それらは無視します。総てのセルにセットし終えたところで処理は終了です。

 例えば、rngが2×2の4つのセルからなる領域である場合、

   rng.Data = %w(awk perl python ruby)

とすれば、1行目に awk, perl、2行目に python, ruby が書き込まれます。

 なお、「rng.Data = "xyz"」のように右辺に配列でないもの(文字列や数値)を置いた時は、rngの左上端のセル1つにそれをセットして終了します。

(5) 領域の縦・横の幅を返す max_row(), max_col(), max_y(), max_x()

 rng.max_row() は、領域内に含まれる行数(縦の幅)を返します。値は 1以上。

 rng.max_col() は、領域内に含まれる列数(横の幅)を返します。値は 1以上。

 rng.max_y() は、max_row() よりも1少ない値を返します。値は0以上。

 rng.max_x() は、max_col() よりも1少ない値を返します。値は0以上。

(6) 領域内の更に小さい部分領域を返す range()

 rng.range() は、領域内の更に小さい部分領域を返します。

   rng2 = rng.range(0,0, 2,2)
   rng3 = rng.range(1,1)

などのように用います。終点の番地を省略した時は、セル1つのみを含む領域を返します。

 引数として与えられた番地が範囲外である場合は false を返します。

(7) 領域の番地をワークシート上における番地として返す address()

 rng.address() として、引数を指定せずに呼び出すと、rngが示す領域の始点と終点の番地(4つの整数値)を返します。これは、ワークシート上における番地です。領域内における相対的な番地ではありません。

   rng = ss.range(1,1, 3,3)
   p rng.address()  # => [1,1, 3,3]

 一方、rng.address(0,0) とすれば、領域内の 0,0 のセル(つまり左上端のセル)の番地を返します。領域内における相対的な番地ではなく、ワークシート上における番地です。

   rng = ss.range(1,1, 3,3)
   p rng.address(0,0)  # => [1,1]

 引数が不適当な場合は nil を返します。

(8) 指定した1行を領域として返す row_range(y)

 領域内の1行だけを対象に何か処理したい場合、

   rng2 = rng.row_range(0) 

とすれば、第1行目のみがrng2にセットされます。rng2もExlRangeオブジェクトです。

 引数として渡すのは、行の番号に当たる数値で、0以上の整数です。

 引数が不適当な時は false を返します。

(9) 指定した1列を領域として返す col_range(x)

 領域内の1列だけを対象に何か処理したい場合、

   rng2 = rng.col_range(0) 

とすれば、第1列目のみがrng2にセットされます。rng2もExlRangeオブジェクトです。

 引数として渡すのは、列の番号に当たる数値で、0以上の整数です。

 引数が不適当な時は false を返します。

(10) 領域内の各セルを扱うための each および each_with_yx

 領域内の各々のセルを扱う場合、次のような記述が可能です。

     rng.each {|cell|  cell.Font.Size = 14}

 上の記述において変数cellは、必ず構造体的Hashです。空欄は {} です。

 この each は、常にブロック付きで利用します。ブロックがなければ何もしません。

 領域内のセルを1つづつ変数cellにセットして反復するわけですが、ただし、セル結合されている空欄セルは飛ばします。セル結合範囲の左上端のセルは飛ばしませんが、それ以外の結合されている空欄セルを飛ばします。

 eachの戻り値は self です。

 同じような働きをするメソッドに each_with_yx というのもあります。cellの他にy,x座標値を参照できるものです。

     rng.each_with_yx do |cell, y, x|
       next  if y == 0
       cell.Font.Color = "Blue"
     end

というように記述します。上は、第1行目以外の各セルの色を青色にするものです。

 y,x は 0以上の整数値です。

 セル結合されている空欄セルは飛ばします。

 eachの戻り値は self です。

(11) 領域の内容を消去する clear()

 rng.clear() を実行すると、領域内の各セルが総て nil になります。

 戻り値は self です。

(12) 領域内の各セルを罫線で囲む allbox(line_style, weight, color)

 rng.allbox() とすれば、領域内の各セルを罫線で囲みます。

 引数に指定できるのは、line_style(罫線の種類)、weight(太さ)、color(色)です。省略あるいはnil指定の時は、デフォルト値になります。簡易記述用メソッド eBorder() の場合と同じです。

 戻り値は self です。

(13) 外枠の罫線を引く framebox(line_style, weight, color)

 rng.framebox() とすれば、領域の外枠の罫線を引きます。allbox()と異なり、領域内部には罫線が引かれません。

 引数は、allbox() と同じです。

 戻り値は self です。

(14) 罫線を消去する clearbox()

 rng.clearbox() とすれば、領域内の罫線情報を総て消去します。

 戻り値は self です。

(15) セル結合の設定または解除を行う merge_cells

 「rng.merge_cells = true」とすれば、領域をセル結合します。左上端以外のセルの内容は、消去されます。

 「rng.merge_cells = false」とすれば、領域のセル結合が解除されます。

 戻り値は self です。

(16) セル結合の情報を得るための merge_span()

 「ary = rng.merge_span」とすると、領域内のセル結合情報が ary にセットされます。ary は2次元配列です。

 例えば、領域の左上端が2×2のセル結合範囲の始点である場合、ary[0][0]〜ary[1][1] の4つの要素のうち、ary[0][0] 以外は、[0,0] を値に持つものとなります。この [0,0] は、結合範囲において実際にデータが書き込まれているセル(いわば結合範囲の始点)の番地です。一方、ary[0][0] の値は nil になります。

 得られた ary を手がかりにするとき、その要素が nil の箇所は、実態としてテータが書き込まれているセルであるということになります。

 要素が [0,0] のように配列になっている箇所は、実態としては空欄で、0,0 番地に結合されているということになります。

-----------------------------------------------------------------------------

10. ワークブックを記録するための ExlBook クラス

 ExlBookクラスについては既に言及していますが、改めて説明を記します。

 このクラスについて述べる前に、このクラスの基盤部分を ExlBookBase というクラスにしてあるので、それについて先ず述べます。

 ExlBookは、この基盤クラスから導出されています。なので、以下に記すメンバー変数とメソッドは、総て ExlBookクラスのものとして使うことができます。

(1) ExlBookBaseのメンバー変数

 このクラスは、以下のメンバー変数を持ち、情報を記録・保持します。

  • ワークシート情報 @sheets(配列) (デフォルトは [] の空配列)
     この配列に ExlSheetオプジェクトが記録されます。
     1つのExlSheetオプジェクトを参照するには @sheets[0] とか @sheets.last などとします。
  • 作成者 @author(文字列) (デフォルトは nil)
     xmlssの作成者名をこれで指定します。nilの時は __author__ になります。
  • 最終作成者 @last_author(文字列) (デフォルトは nil)
     xmlssの最終作成者名。nilの時は __last_author__
  • 所属 @company(文字列) (デフォルトは nil)
     会社名等をこれで指定。nilの時は __company__
  • 作成日時 @created(文字列) (デフォルトは nil)
     ワークブックの作成日時。nilの時は xmlss出力時に現在日時がセットされる。値は世界標準時(日本時間より9時間遅い)で '2010-12-11T10:53:20Z' のような形。
  • 最終保存日時 @last_saved(文字列) (デフォルトは nil)
     ワークブックの最終保存日時。xmlss出力時は必ず現在日時に更新される。値は @created と同形式。
  • 対応外のエレメント情報 @other(Hash) (デフォルトは {})
     これについては ver 1.2.2→1.2.3のバージョンアップ履歴を参照。

 これらメンバー変数は、いずれも読み書き両方許可です。

   wb = ExlBookBase.new
   wb.author = "高橋一郎"
   puts wb.company
   wb.sheets.each {|ss|
     puts ss.name  # ワークシート名
   }

のように使うことができます。

(2) xmlssを文字列の形で得るための xml_string()

 xmlssのソースを文字列の形で得たい場合、この xml_string() を用います。

(3) xmlssをファイルとして出力するための output_xml(filename)

 xmlssをファイルとして書き出す時に、この output_xml(filename) を用います。別名として xml_output を用いることもできます。

 引数はファイル名です。

 上書きで書き出します。同名のファイルがある場合、それは失われるので注意して下さい。

(4) csvをファイルとして出力するための output_csv(filename)

 メンバー変数 @sheets をcsvファイルとして出力したい時に、この output_csv(filename) を用います。別名 csv_output。

 ファイルは、上書きで書き出します。同名のファイルがある場合、それは失われるので注意して下さい。

 表が複数ある時は、表と表の間に空白行を2行か3行設けます。

 csvの漢字コードは、Shift_JISになります。これを変更したい時は、グローバル変数 $ExlapCsvCの値を変更します。

 's' なら Shift_JIS, 'e' なら euc-jp, 'w' だと utf-8 です。$ExlapCsvCは、nkfのオプション文字として使われます。

(5) web(html)を文字列の形で得るための web_string(title), web_array()

 web(html)のソースを文字列の形で得たい場合、この web_string(title) を用います。

 引数としてwebのタイトルを渡すことができます。

 web_string('test page') のようにします。引数を省略した時は 'no title' になります。

 webに変換する際、セル結合以外の情報(font, alignment, bordersなど)は捨てます。色や文字の大きさなどは、webに反映されません。

 各々のワークシートが <table> …… </table> として出力されます。

 ワークシート名は、<table>の直前に <h2>……</h2> の形で出力されます。

 各ワークシートを各々別個のhtmlソースとして得たい時は、web_array() を用います。このメソッドに引数はありません。

 このメソッドを呼び出すと、1つのワークシートが「<h2>シート名</h2> <table>シート本体</table>」の形式に変換され、それが複数記録された配列を返します。第1のシートを取り出すなら、wb.web_array[0] のようにします。

(6) webをファイルとして出力するための output_web(filename, title)

 webをファイルとして書き出す時に、この output_web(filename, title) を用います。別名 web_output。

 引数はファイル名とwebのタイトルです。webのタイトルを省略すると 'no title' になります。

 上書きで書き出します。同名のファイルがある場合、それは失われるので注意して下さい。

 以上が ExlBookBaseクラスの仕様です。

 これらは、総てExlBookに継承されます。

 また、後述の ExlWeb(webを扱うためのクラス)、ExlCsv(csvを扱うためのクラス)の両者とも、このExlBookBaseの継承クラスです。

 ExlBook, ExlWeb, ExlCsv は、いずれも ExlBookBaseに独自のpushメソッドを追加したものです。

 pushメソッドは、urlとかcsvなどの外部の情報を取り込むためのメソッドです。

(7) ExlBookのweb_pushメソッド

 web_pushは、urlやhtml_stringを受け取るためのものです。別名 push_web。

 受け取った情報を基に、webのtableを抽出します。ここでいうtableは、入れ子になっていないtableです。つまりtableの中に更にtableが含まれているものは対象外とします。

 該当するtableが複数ある場合は、それらを総て2次元配列に変換して記録します。条件に該当するものだけ記録することも可能。

 配列に変換する際、その漢字コードをexlap_cライブラリと同じになるよう調整します。

 戻り値は self です。

   wb.web_push(url1, url2, url3, ……)

のように、引数を必要なだけ渡すことができます。

 渡された引数が "<……" のように半角の '<' で始まり、'<html' および '</html>' を含む文字列であれば、urlではなくhtml_stringとみなして処理します。この判定のとき、文字列先頭の空白や改行は無視します。

 記録するtableを限定したい時は、行数(tableに含まれる<tr>の個数)が何行以上かを指定する方法と、table部分のhtml_stringに対して正規表現でのマッチングを行う方法があります(下記の例を参照)。

   wb.web_push(url, 5)  # 5行以上あるtableを抽出
   wb.web_push(url, /ID="press\d+"/i)
       # ↑ tableのhtml_stringが指定の正規表現とマッチするものを抽出
   wb.web_push(url1, /ID="press\d+"/i, 5, url2, url3)
       # ↑ 正規表現と行数指定を合わせて指定可能。両条件とも満たすものを抽出

(8) ExlBookのcsv_pushメソッド

 csv_pushは、引数として渡されたcsv_filenameやcsv_stringから、csvデータを受け取るためのものです。別名 push_csv。

 csvデータを配列に変換する際、その漢字コードをexlap_cライブラリと同じになるよう調整します。

 1まとまりのcsvデータを1つのワークシートとして記録します。

 戻り値は self です。

 渡された引数が改行コードを含む文字列である場合、csv_filenameでなく csv_string であると判断します。

 引数がfilenameでなくstringであることを明らかにしたい時は、その引数の直後に、ラベル :STRING を引数として渡します。

   wb.csv_push(str, :STRING)

 逆に、filenameであることを明らかにしたい時は、ラベル :FILE をすぐ後に渡します。

   wb.csv_push(filename, :FILE)

 引数は、必要な数だけ渡すことができます。

   wb.csv_push(filename, :FILE, str, :STRING, "input.csv", csv_str)

   csv_str = "セルA1,セルB1\n\nセルA3,セルB3\n"
   wb.csv_push(csv_str)

(9) ExlBookのpushメソッド

 pushメソッドは、上記の web_push, csv_push の機能を合わせ持つメソッドです。

 渡された第1引数の状況に応じて、内部で web_push または csv_push を呼び出します。

 url と csv_filename などを混在して渡すと、うまく処理されないので注意して下さい。あくまで第1引数を手がかりにして振り分けているだけです。

 戻り値は self です。

   wb.push(url)
   wb.push(csv_filename)

のように複数回呼び出すと、その都度、内部のワークシート情報が蓄積されていきます(@sheetsに情報が追加されていきます)。

 そして、最後に wb.output_xml("test.xml") とすれば、蓄積されていたワークシート情報が総て書き出されます。

 引数が1つだけの時は、push の代わりに << を用いることもできます。

   wb << url
   wb << csv_str

のように書けます。

(10) ExlBookのxml_pushメソッド

 xml_pushは、xmlssを取り込むためのメソッドです。別名 push_xml。

 このメソッドに渡す引数は、xmlssのファイル名、url、文字列のどれかです。

 引数は1つのみ渡します。カンマで区切って複数指定することはできません。ただし、メソッドを複数回呼び出すて、複数のxmlssを取り込むことは可能です。

   wb = ExlBook.new
   wb.xml_push 'test.xml'
   wb.xml_push 'http://www.hoge.com/test.xml'
   wb.xml_push '<?xml version="1.0" …… </Workbook>'

 xmlssの作成者(author)、最終作成者(last_author)、所属(company)、作成日時(created)が未定義の場合、取り込んだxmlssの値がセットされますが、先に取り込んだものが優先されます。

 ワークシート名が重複する場合は、適当に調整されます。

 取り込んだxmlssのワークシートは、内部的に2次元配列として記録しますが、いずれの要素もHashとなります。

 exlap_cライブラリで扱っていない情報は、取り込まずに捨てます。例えば、印刷用レイアウト情報等を含む WorksheetOptions は取り込みません。

 xml_push() の戻り値は self です。

 xmlssの解析には ruby標準ライブラリの rexml を用いています。

-----------------------------------------------------------------------------

11. webのtableを扱うためのExlWebクラス

 webのtableを扱うためのクラス ExlWeb があります。

 ExlBookBaseクラスを継承しているので output_xml, output_csv などのメソッドを使えます。

 webを取り込めば十分という場合(csvを取り込む必要はない)、このExlWebクラスで大丈夫です。

 webのtableを取り込む時は push メソッドを用います。これは、ExlBookクラスのweb_pushと同じ仕様です。

 table部分にcaption情報が含まれていれば、2次元配列の第1行目に、「caption:……」が挿入されます。

 その他、webを扱うためのメソッドがいくつか含まれています。

 例えば、table部分をrubyの配列に変換するための table_to_array() など。詳細はスクリプトを参照して下さい。

 なお、このExlWebクラスのオブジェクトを生成する際、nokogiri または hpricot がrequireされていなければ、nokogiri → hpricot の順でrequireを試みます。(ruby v1.9系では hpricotのrequireは試みません。)

 ExlBookクラスのweb_pushメソッドは、内部でExlWebを生成しているので、htmlパーサのrequireに関するこのルールが同じように適用されます。

-----------------------------------------------------------------------------

12. csvを扱うためのExlCsvクラス

 csvを扱うためのクラス ExlCsv があります。

 ExlBookBaseクラスを継承しているので output_xml などのメソッドを使えます。

 csvを取り込めば十分という場合(webを取り込む必要はない)、このExlCsvクラスで大丈夫です。

 csvを取り込む時は push メソッドを用います。これは、ExlBookクラスのcsv_pushと同じ仕様です。

 exlap_cライブラリでは、標準添付ライブラリのcsv または FasterCSV を利用して、csvの取り込みと書き出しを行うようにしています。

-----------------------------------------------------------------------------

13. クラスに属していないメソッド一覧

 eFont() など、クラスに属していないメソッドについて、既に随所で述べましたが、まだ紹介していないものもあるので、改めてここで一覧を掲げておきます。

 なお、これらメソッドは、いずれも module Exl に属しています。利用する時は、頭に「Exl::」を付けるか、スクリプトの適当な箇所に「include Exl」を置いて下さい。

○ eData(data, hash1, hash2, ……)

 dataをhash形式に変換。第2引数以降があれば、それらをhashに結合。

例: eData("ruby", {'Font'=>{'Color'=>"Blue"}}) # => {'Data'=>"ruby", 'Font'=>{'Color'=>"Blue"}}

○ eFont(color, font_name, size)

 font情報をhash形式に変換。

例: eFont("#FFFFFF", "MS Pゴシック", 14) # => {'Font'=>{'Color'=>"#FFFFFF", 'FontName'=>"MS Pゴシック", 'Size'=>14}}

○ eAlignment(horizontal, vertical, wrap)

 文字の配置を指定。横方向の位置、縦方向の位置、行の折り畳みon/offを指定。

例: eAlignment("Left", "Top", 1) # => {'Alignment'=>{'Horizontal'=>"Left", 'Vertical'=>"Top", 'WrapText'=>1}}

○ eInterior(color, pattern)

 セルの背景色を指定。

例: eInterior("#000000", "Solid") # => {'Interior'=>{'Color'=>"#000000", 'Pattern'=>"Solid"}}

○ eSpan(cspan, rspan)

 セル結合を指定。横方向の結合、縦方向の結合の順で指定。値2以上が結合を意味。

例: eSpan(2, 3) # => {'span'=>{'Cspan'=>2, 'Rspan'=>3}}

○ eBorder(line_style, weight, color)

 罫線を指定。引数は、線の種類(実線|点線)、線の太さ、線の色。

 セルの上辺、底辺、左辺、右辺を引く eBorder_t, eBorder_b, eBorder_l, eBorder_r もある。

例: eBorder("Continuous", 1)

  eBorder("Dot", 1, "Blue")

○ eNumberFormat(string)

 数値型や日付・時刻型の表示形式を指定。

例: eNumberFormat("000") # => {'NumberFormat'=>"000"}

○ eFormula(string)

 Excelの計算式や関数を指定。

例: eFormula("=SUM(RC[-3]:RC[-1])") # => {'Formula'=>"=SUM(RC[-3]:RC[-1])"}

○ eType(string)

 セルのデータ型を指定。

例: eType("String") # => {'Type'=>"String"}

○ eWidth(n)

 列の幅を桁数(半角文字での数)指定。

例: eWidth(10) # => {'Width'=>"65"}

○ eHeight(n)

 行の高さを指定(何行分の高さかの指定)。

例: eHeight(3) # => {'Height'=>"40.5"}

○ ePhoneticText(string, n)

 ふりがなを指定。第2引数として1を与えると、ふりがな表示の指定になる。

例: ePhoneticText("ソウリダイジン") # => {'PhoneticText'=>"ソウリダイジン"}

   ePhoneticText("ソウリダイジン", 1)  # => {'PhoneticText'=>
       {'Text'=>"ソウリダイジン", 'Visible'=>1}}

○ eHidden(n)

 行や列の非表示属性を指定。引数は1または0。

例: eHidden(1) # => {'Hidden'=>1}

○ eHRef(string)

 ハイパーリンクのurlを指定。

例: eHRef('http://jp.rubyist.net/magazine/')

○ eNamedCell(string)

 名前付き範囲のNamedCellを指定。

例: eNamedCell('ruby関連')

○ getData(x)

 2次元配列の要素のデータを得る。要素がHashか否かにかかわらずデータを返す。

例: getData(aa[0][0]) # => "ruby"

○ convert_for_csv(ary)

 2次元配列をcsv用に変換。配列の要素がhashだと、そのままではcsvにできないので、総て文字列に変換する。

 また、漢字コードは Shift_JIS に変換($ExlapCsvCに従う)。

 引数を複数与えると、変換した結果を大きな配列に入れて返す。大きな配列の各要素は2次元配列。

例: new_ary = convert_for_csv(ary)

    csv_ary = convert_for_csv(ary1, ary2, ary3, ……)
    csv_ary.each {|ary|
        …………
    }

○ arrange_array(ary, code, form)

 2次元配列の漢字コードなどを変換して返す。

 codeは漢字コード('e', 's', 'w')、

 formが :TO_STRING だと各要素を文字列に変換(hashを変換)。:TO_HASHならHash形式に変換。nil ならhashの変換はしない。

例: new_ary = arrange_array(ary, 'e', :TO_STRING)

○ hash_structize(obj)

 引数 obj がHashのとき、それを構造体的Hashに変換して返す。objの要素にHashがあると、それらも総て構造体的Hashに変換する。

 objがHashでない時は、何も変換せず obj を返す。

例: hash_structize({'Font'=>{'Size'=>14}})

○ abs_rc(y,x)

 座標 y,x をExcelのRC方式(絶対番地)で表現した文字列として返す。

例: abs_rc(1,2) # => "R2C3"

○ rel_rc(y,x)

 相対的な座標 y,x をExcelのRC方式で表現した文字列として返す。

 rel_rc(3,4) は、現在注目セルの3行下、4列右を示す。

例: rel_rc(1,2) # => "R[1]C[2]"

  rel_rc(4,0) # => "R[4]C"

  rel_rc(0,-1) # => "RC[-1]"

-----------------------------------------------------------------------------

14. その他

  • 2次元配列のHash要素について、そのkey('Data', 'Font'など)は、頭文字を大文字にします。Excelが書き出すxmlssに倣ったものです。
  • アラビア数字は、全角で書いてあっても内部的に半角に変換して表示形式を判別処理します。その上で、数値型と判別されれば、全角を半角に変換して記録します。
     例えば、全角の「123」も数値として扱います。アラビア数字のほか、カンマ、ピリオド、パーセント、スラッシュ、マイナス、コロンの記号は、全角であっても内部的に半角変換して判別処理します。
  • 次の文字は、文字化けを避けるため、xmlss作成の際に数値文字参照に置き換えています(例えば &#65374; など)。
     「〜 − ‖ ¢ £ ¬ 」
  • fontやalignmentなどのスタイル情報の1つに protection があるようです。一応、Hashで記述すれば対応可能だと思いますが、どのように使うのか、web検索してもよく分かりませんでした。実際に対応できるか否かは不明です。
  • 太字のBold、斜体のItalicは、fontで指定しますが、eFont() ではサポートしてないので、Hashで指定して下さい。構造体的Hashで記述するなら次のとおり。
      cell.Font.Bold = 1
      cell.Font.Italic = 1

-----------------------------------------------------------------------------

15. バージョンアップ履歴

□ exlap_c ver 1.2.4 → 1.3

 かなり変更を加えましたが、主な点は次のとおり。マニュアルも相当量 追加・修正しましたので、詳細はマニュアル本文を参照して下さい。

  • 構造体的Hashを採用した。
  • ワークシート内の一定の領域を扱うための ExlRangeクラスを新たに設けた。また、それに合わせて ExlSheetクラスににExlRangeに関連するメソッドをいくつか設けた。
  • ワークシートが空の時に、適切なxmlssを出力できなかったバグを修正。
  • 既存のxmlssを取り込んだ時に、その文字コードがutf-8のままになっていたため(つまりベース文字コードと一致しなかったため)、文字化けになるケースがあったバグを修正。

□ exlap_c ver 1.2.3 → 1.2.4

 他のライブラリとメソッド名が衝突しないよう、クラスに属していないメソッドをmodule化しました。それ以外の変更はありません。機能的には v1.2.3 と同じです。

 以下のメソッドをmodule Exl の下に収納しました。そのため、それらメソッドを使う時は予め include Exl するか、もしくは、Exl::eData(……) のようにメソッド名の前に「Exl::」を付けます。

  • eData, eFont など、小文字の 'e' に続いて大文字がくるメソッド
  • getData(2次元配列の要素のデータを得る)
  • convert_for_csv(2次元配列をcsv用に変換)
  • arrange_array(2次元配列の文字コードや形式を変換)

 なお、上記以外のクラスに属さないメソッドは、module ExlPrivate の下に集約しました。

□ exlap_c ver 1.2.2 → 1.2.3

 主な変更点は次の4つ。今回の眼目は、exlap_cライブラリが取り扱わない情報の取込み/書き出しを行えるようにしたこと。これにより、例えば、印刷レイアウト情報の付加、ドロップダウンリスト(選択入力欄)設定等が可能になる。

  • ふりがなの表示/非表示の指定を行えるようにした。
  • ハイパーリンクの指定を行えるようにした。
  • 各々のセルのNamedCell情報を扱えるようにした(名前付き範囲の設定に必要)。
  • exlap_cライブラリが取り扱わない情報の取込み/書き出しを行えるようにした。

1) ふりがなの表示/非表示の指定を行えるようにしました。

 ふりがなは、HashのPhoneticTextで指定しますが、次のようにすると、ふりがな表示を指定することになります。

   ary[0][0] = {'Data'=>"総理大臣",
       'PhoneticText'=>{'Text'=>"ソウリダイジン",
       'Visible'=>1}}

 ちなみに、非表示のままでよければ次の記述で大丈夫です。

   ary[0][0] = {'Data'=>"総理大臣",
       'PhoneticText'=>"ソウリダイジン"}

 簡易記述用メソッド ePhoneticText() を用いる場合は次のように書けます。

   eData("総理大臣", ePhoneticText("ソウリダイジン"))  # 非表示
   eData("総理大臣", ePhoneticText("ソウリダイジン", 1))  # 表示

2) ハイパーリンクの指定を行えるようにしました。

 ハイパーリンクは、HashのHRefで指定します(最初の2文字が大文字)。一例は次のとおり。

   ary[0][0] = {'Data'=>"ルビマ",
       'HRef'=>"http://jp.rubyist.net/magazine/"}

 簡易記述用メソッド eHRef() を用いると次のように書けます。

   ary[0][0] = eData("ルビマ", eHRef("http://jp.rubyist.net/magazine/"))

3) 各々のセルのNamedCell情報を扱えるようにしました。

 NamedCellは、名前付き範囲の設定に関わるものです。例えば、A1欄からB2欄までの2×2の領域を名前付き範囲として設定する場合、この4つのセルにNamedCellで名前を付けます。A1欄に名前を付ける例は次のとおり。

   ary[0][0] = {'Data'=>"ルビマ", 'NamedCell'=>"ruby関連"}

 簡易記述用メソッド eNamedCell() を用いると次のように書けます。

   ary[0][0] = eData("ルビマ", eNamedCell("ruby関連"))

 これはA1欄1つのみを設定する例ですが、2×2の4つのセルに対して同じように設定します。

 ただし、名前付き範囲を設定するためには、この他に xmlssソースにおいて

   <Names><NamedRange ……></Names>

という記述をWorkbookエレメントの内側に書く必要があります。これについてはexlap_cライブラリが直接サポートしていませんが、次項に記す「exlap_cライブラリが取り扱わない情報の取込み/書き出し」で可能になります。

 名前付き範囲の設定は、例えば、選択入力欄(ドロップダウンリスト)を設定する時に必要になります。そのサンプルが付属の sample02.rb です。

4) exlap_cライブラリが取り扱わない情報の取込み/書き出しを行えるようにしました。

 exlap_cライブラリは、例えば、印刷用レイアウト情報の WorksheetOptions を直接扱う機能を持っていません。そこで、そうした情報をxmlssソースで取り込んだり書き出したりする仕組みを設けました。

 ExlBookBaseクラスおよびExlSheetクラスにメンバー変数 @other を設けました。この変数はHashを記録するもので、初期値は {} です。

 ExlBookBaseの@otherに記録されたものは、xmlss出力時にWorkbookエレメントの内側に挿入されます。ExlSheetクラスの@otherは、Worksheetエレメントの内側です。

 例えば、WorksheetOptionsエレメントを記録するなら、次のようにします。

   ss = ExlSheet.new
   ss.other['WorksheetOptions'] = <<EOS
   <WorksheetOptions ……>
   <PageSetup>
   <Header ……>
   <Footer ……>
   ……
   </PageSetup>
   …………
   </WorksheetOptions>
   EOS

 上のように@otherを設定した上で、output_xml() でxmlssを書き出すと、該当のワークシートに印刷用の情報が付加されます。

 一方、xml_push() メソッドでxmlssを取り込む時に

   wb = ExlBook.new
   wb.xml_push("test.xml", true)

のように第2引数として true を指定すると、exlap_cライブラリが直接サポートしない情報が@otherに記録されます。ExlBookの@other、ExlSheetの@otherの両方にそれぞれの情報が記録されます。

 したがって、このようにしてtest.xmlを取り込んだ上で

   wb.output_xml "test02.xml"

として書き出すと、test.xml と test02.xml は、完全に同じ内容とはいえないにしても、概ね同じ内容になると思います。

 xml_push()の第2引数は、正確には、trueでなくても「nilかfalse」以外であれば同じです。第2引数を指定しなければnilが指定されたものとみなされます。つまり @otherには何も記録されません。

 xml_push()を複数回呼び出して、2つ以上のxmlssを取り込んだ場合、@otherには複数のxmlssの情報がごちゃごちゃになって記録されます(どんどん追加記録されていきます)。これはトラブルの原因になるので、@otherに情報を記録する形でxmlssを取り込む時は、1つのみに限るのが無難です。

 なお、exlap_cライブラリが取り扱う情報は次のとおり。

  • Workbookの内側:
      DocumentProperties(Author, LastAuthor, Company, Created, LastSaved)
      Styles(Font, Alignment, Borders, NumberFormat など)
      Worksheet(Tableのみ)
  • Worksheetの内側:
      Table(これには Column, Row, Cellなどの子要素が含まれる。)
      (Table以外は対象としない。)

 Workbookに属する他のエレメントとしては、OfficeDocumentSettings, ExcelWorkbook, Names などがあるようです。

 Worksheetに属するものとしては、WorksheetOptions, DataValidation, Names などがあるようです。

 名前付き範囲の Names は、場合によって Workbook に属したり Worksheet に属したりするようです。

 DataValidationは、選択入力欄(ドロップダウンリスト)の設定に関わります。

 xmlssの正確・詳細な仕様は、webでは見あたらないように思います。各エレメントの働きを知るには、Excelで書き出したxmlssから推測するしかないのでは?という気がします。

□ exlap_c ver 1.2.1 → 1.2.2

 主な変更点は次の3つ。

  • Formula式の出力を「有|無」する変数$ExlapFormulaOutを設けた。
  • Excelの「非表示」への対応。
  • Excelの「ふりがな」への対応。
  • その他、バグ修正。

1) Formula式の出力を「有|無」する変数$ExlapFormulaOutを設けました。

 csvやwebとして出力する際に、Formulaの計算式や関数を出力するかどうかをグローバル変数$ExlapFormulaOutで制御できるようにしました。出力されると結構じゃまなので(あせ)。

 $ExlapFormulaOut の初期値は nil。

 これがnilかfalseだと、csv, web を出力する際に Formula式を出力しません。それ以外(trueなど)なら出力します。

2) Excelの「非表示」に対応しました。

 グローバル変数 $ExlapHiddenOut(初期値は nil)がtrueだと、csv, web を出力する際に、行や列に非表示属性(Hidden)が付いていても出力します。ちなみに、Excelによりcsvを書き出した時は非表示のものも出力されます。

 nil または false だと出力しませんが、非表示属性の付いた行や列を空欄にするだけで削除はしません。つまり、行や列の数は変化しません。

 :DELETE の場合は、空欄にするのではなく削除します。したがって、行や列の数が少なくなります。 この :DELETE の場合、セル結合のある2次元配列をweb出力する時は、意図したような出力結果にならない可能性があるので、:DELETE よりも nil の方が無難です。

 非表示の処理は、オリジナルの2次元配列に変更を加えるわけではなく、csv, web を出力する際、2次元配列のコピーを作り、それに非表示の処理を施して出力します。

 なお、非表示属性の指定は Hash で行います。例えば、ssがExlSheetクラスのオブジェクトのとき、

   ss.col[0] = {'Hidden'=>1}

とすれば、第1列目が非表示となります。簡易記述用メソッド eHidden() を用いて

   ss.col[0] = eHidden(1)

と書くこともできます。

   ss.row[1] = eHidden(1)

とすれば、第2行目が非表示となります。

3) Excelの「ふりがな」に対応しました。

 ふりがなを扱えるようにしました。HashのPhoneticTextで指定します。

 例えば、2次元配列の1つの要素を

   {'Data'=>"総理大臣", 'PhoneticText'=>"ソウリダイジン"}

のようにします。簡易記述用メソッド ePhoneticText() を設けたので、次のように書くこともできます。

   eData("総理大臣", ePhoneticText("ソウリダイジン"))

 xml_push() でxmlssを取り込んだ時も、ふりがなデータが取り込まれます。

 変数$ExlapPhoneticTextOutがnilかfalseなら、csv, web出力時に、ふりがなを出力しません。それ以外(trueなど)なら出力します。デフォルトは nil です。

 ちなみに、Excelにはふりがなを取り出す関数 PHONETIC() があります。例えば、B1欄に「=PHONETIC(RC[-1])」と書き込んであると、左隣(A1欄)のふりがな情報がB1欄に表示されます。

4) その他、バグ修正

 xml_push()でxmlssを取り込む際、Font, Alignment などのスタイル情報の取込みに失敗し、エラーが発生して中断してしまうケースがあったのを修正しました。

□ exlap_c ver 1.1 → 1.2.1

 変更点は次の6つ。眼目は、xmlss, csv, html それぞれについて入力と出力の双方を行えるようにしたこと。

  • xmlssを取り込めるようにした。
  • htmlを出力する機能を付加。
  • セル内の一部に色を付けるなどの部分的指定を可能にした。
  • 表・列・行の各単位でfontやalignmentの設定ができるようにした。
  • csv|html出力時に、NumberFormatに即してデータの書式を整えるようにした。
  • Formula式の代替rubyスクリプトを定義できるようにした。

1) xmlssを取り込めるようにしました。

 ExlBookクラスに、xml_push() メソッドを設け、これによりxmlssを取り込めるようにしました。

 このメソッドに渡す引数は、xmlssのファイル名、url、文字列のどれかです。

 引数は1つのみ渡します。カンマで区切って複数指定することはできません。ただし、メソッドを複数回呼び出すて、複数のxmlssを取り込むことは可能です。

   wb = ExlBook.new
   wb.xml_push 'test.xml'
   wb.xml_push 'http://www.hoge.com/test.xml'
   wb.xml_push '<?xml version="1.0" …… </Workbook>'

 xmlssの作成者(author)、最終作成者(last_author)、所属(company)、作成日時(created)が未定義の場合、取り込んだxmlssの値がセットされますが、先に取り込んだものが優先されます。

 ワークシート名が重複する場合は、適当に調整されます。

 取り込んだxmlssのワークシートは、内部的に2次元配列として記録しますが、いずれの要素もHashとなります。

 exlap_cライブラリで扱っていない情報は、取り込まずに捨てます。例えば、印刷用レイアウト情報等を含む WorksheetOptions は取り込みません。

2) htmlを出力する機能を付加しました。

 取り込んだ各種データ(2次元配列、csv、html、xmlss)をhtml形式の文字列に変換する web_string(title) メソッドを設けました。ExlBookBaseクラスのメソッドです。なので、ExlBook, ExlWeb, ExlCsv の各クラスにおいて利用できます。

 引数 title を与えると、それがwebページのタイトルとなります。省略すると 'no title' となります。

 webに変換する際、セル結合以外の情報(font, alignment, bordersなど)は捨てます。色や文字の大きさなどは、webに反映されません。

 各々のワークシートが <table> …… </table> として出力されます。

 ワークシート名は、<table>の直前に <h2>……</h2> の形で出力されます。

 また、各ワークシートを別々のhtmlソースとして得たい時は、web_array() を用います。このメソッドに引数はありません。このメソッドを呼び出すと、1つのワークシートが「<h2>シート名</h2> <table>シート本体</table>」の形式に変換され、それが複数記録された配列を返します。第1のシートを取り出すなら、wb.web_array[0] のようにします。

 それから、webに変換したものをファイルに書き出しためのメソッド output_web(filename, title) も設けてあります。

   wb = ExlBook.new
   wb.output_web 'test.htm', 'test page'

のように用います。

3) セル内の一部に色を付けるなどの部分的指定を可能にしました。

 例えば「あいうえおかきくけこ」のうち「あいうえお」だけを赤色にしたい場合、2次元配列の1つの要素を次のようにセットします。

   ary[0][0] = eData(
       '<Font html:Color="Red">あいうえお</Font><Font>かきくけこ</Font>',
       eType('String@html'))

 データの型として 'String@html' のように '@html' を付加すると、そのデータはhtml形式で記述されているものとして処理されます。

 html形式といっても、一般的なhtml記述のルールとは異なるように思いますが、正確な仕様は分かりません。

 <I>……</I>でイタリック、Bなら太字、Uなら下線、といったタグが使えるようです。

 誤って記述すると、読み込みのできないxmlssになってしまうので注意して下さい。

 通常のデータは、xmlssにおいて <Data ss:Type="String">……</Data> などのようになりますが、Typeに 'String@html' を指定した場合は、<ss:Data ss:Type="String">……</ss:Data> に変換されます。

 html形式の場合、当然ながら、'<' を '&lt;' に変換するといった処理は施しません。通常のデータについては、exlap_cライブラリがその種の変換を施します。

4) 表・列・行の各単位でfontやalignmentの設定ができるようにしました。

 ExlSheetクラスの @row, @col は、それぞれ行、列に関する情報(行の高さ、列の幅)を記録するためのものですが、これらにFontやAlignmentなどのスタイル情報を記録できるようにしました。1列目は総て青、2列目は総て赤といった設定が可能です。

 また、表全体についてのスタイル情報を記録できるように、メンバー変数 @tbl も設けました。

   ss = ExlSheet.new
   ss.tbl = eFont("Green")

とすれば、表全体を通して、文字の色が緑になります。

 色を緑に設定して、かつ、総てのセルを罫線で囲みたい時は

   ss.tbl = eFont("Green").update(eBorder())

のようにします。update() は、Hashを結合・更新するruby標準のメソッドです。

 第1列目を総て赤にしたい時は

   ss.col[0] = eFont("Red")

とします。

5) csv|html出力時に、NumberFormatに即してデータの書式を整えるようにしました。

 これまでは、NumberFormatを参照せず、単純に文字列に変換するだけでした。

 例えば、データが0.5、NumberFormatが '0%' なら、Excelでは「50%」と表示されます。しかし、exlap_cライブラリでcsv出力した時は、「0.5」のままでした。これを「50%」になるように改めました。html出力時も同様です。

 ExcelのNumberFormat処理に完全に対応するのは難しいのでやっていませんが、001問題、小数点以下の桁数調整、パーセント表示、数字のカンマ区切り、日付の表示(Short Date, Long Date, 典型的元号)、時刻の表示(Short Time, h:mm:ss)には対応しています。

 それから、セルに計算式や関数が埋め込まれている場合、xmlssに書き込まれているデータ(不正確な可能性あり)に加えて、Formulaの式を出力するようにしました。ただし、そのFormulaの式に対応するrubyスクリプトが定義されている場合(次項参照)、または変数$ExlapFormulaOutがnilかfalseの場合は出力しません。ちなみに、$ExlapFormulaOutのデフォルト値はnil。

 例えば、関数が埋め込まれているセルをcsvに出力した場合、「123 |=SUM(RC[-3]:RC[-1])」のように出力されます。

 123は、xmlssに書き込まれていた値です(不正確かもしれません)。それに続いて半角スペースと'|'、そして '=SUM……' の関数記述が続きます。

 クラスに属さないメソッド arrange_array() で2次元配列を変換した場合も、第3引数に :TO_STRING を指定すると、上記のNumberFormat, Formula を参照する形で各要素(セル)の変換が行われます。

6) Formulaの式に対応するrubyスクリプトの定義

 セルにFormulaの式が埋め込まれていると、Excelで開いた時はちゃんと計算結果が表示されますが、exlap_cライブラリでcsvやwebに変換した場合は、先述したように、とりあえずの値と式を出力します。

 ただし、その式の代替となるrubyスクリプトが定義されている時は、それに従って計算結果を出力します。式そのものの出力はしなくなります。

 この定義は、グローバル変数 $formula(Hash)で行います。$formulaは、exlap_cライブラリをrequireした時に空のHashとして定義されます(既にHashとして定義されていれば空にしない)。

 $formulaのkeyにはExcel用の式、valueにはrubyスクリプトを記録します。

 例えば、左隣のセルのアルファベット大文字を小文字に変換する例は次のとおり。

   key = "=LOWER(RC[-1])"
   val = "data = getData(aa[rn][cn-1]).to_s.tr('A-Z', 'a-z')"
   $formula[key] = val

 代替のrubyスクリプトにおいて、次の変数は特別の意味を持ちます。

  • aa: 2次元配列
  • rn: 現在の行番号(0以上)
  • cn: 現在の列番号(0以上)
  • data: セルに代入する値をこの変数に入れる。
  • fr_scriptなど: 「fr_」で始まる変数名は、用いないで下さい。

 上記以外のローカル変数は、自由に名前を付けて用いることができます。

 代替のrubyスクリプトにおける漢字コードは、2次元配列のコードと同じになるよう調整されます。スクリプトを書く時に漢字コードを気にする必要はありません。

 その他、getData(param)は、paramがHashならparam['Data']を返し、そうでないならparamそのものを返します。このメソッドは、exlap_cライブラリをrequireした後であればどこででも使えます。クラスには属していません。

7) その他

  • 2次元配列変換用メソッド arrange_array() の第3引数に :TO_HASH を指定すると、各要素がHash形式に変換されるようにしました。{'Data'=>……} の形になります。もともとHashだった時は変換されずそのままです。
  • arrange_array() が2次元配列の複製を返すように改めました。これまでは浅い複製になっていたため、意図しないところで元の配列が変更されてしまう危険性がありました。

□ exlap_c ver 1.0 → 1.1

 変更点は次の3つです。(ライブラリの使い方に特に変更はありません。)

  • rexmlを用いず、ダイレクトにxmlssを生成・出力するよう改めた。
  • 日本語対応部分を明確化した。→他の言語向けの修正がしやすくなった?
  • xmlssの省略可能箇所をなるべく除き、xmlssのサイズを抑制した。

1) v1.0では、いったんrexml用スクリプトを生成し、それを実行することによってxmlssを生成していましたが、v1.1では、直接xmlssを生成します。生成に要する時間が短縮されました。

 これにともない、ExlBookBaseクラスの script_string() メソッドを廃止しました。

2) 日本語対応部分を明確化しました。

 グローバル変数 $ExlapLang を設け、これにシンボル :JAPANESE を代入すると、日本語対応になります。これがデフォルトです。

 一応、$ExlapLang に :ENGLISH を代入すれば英語対応になると思いますが、動作確認はしていません。

 他の言語に対応させる場合、ライブラリスクリプトの $ExlapLang が出てくる辺りをいじれば、対応可能になるのではないかと思います。

 nkfによる漢字処理を別にすれば、言語に依存するのは主に次の2点です。

  • FontName: 日本語のデフォルトは「MS Pゴシック」、英語は「Arial」
  • 日付型の表示形式: 日本語と英語の Long Date, Short Date に対応させたつもり。

3) xmlssの省略可能箇所をなるべく除き、xmlssのサイズを抑制しました。

 例えば、<Row> や <Cell> には、それぞれ何行目、何列目かを明記するための Index属性がありますが、単純に連続している時は省略できます。v1.0では逐一出力していましたが、省略できる時は取り除くようにしました。

 また、空欄であっても <Data ……></Data> が出力されてしまう箇所がありましたが、出力しないよう改めました。

-----------------------------------------------------------------------------

16. ライセンス

 exlap_*.rb, exlap_c.txt のライセンスは、「GNU一般公衆利用許諾契約書(GNU General Public License)」に従います。複製や改変は基本的に自由です。著作権は T. Yoshiizumi が有します。

  参考サイト: http://www.gnu.org/licenses/gpl-faq.ja.html

Copyright (C) T. Yoshiizumi, 2010-2011 All rights reserved.

Last modified:2011/06/28 22:14:38
Keyword(s):[excel] [xmlss] [csv] [web] [table]
References: