Rails と Excel VBA で,XMLファイルを読み書きしよう (MSXMLとREXMLの使い方)
Webアプリ(Ruby on Rails)とデスクトップ(Excel VBA)の間で,XMLをやり取りするサンプルコード。
- VBAでXMLを読み込み(そしてシート上に表示する),
- VBAでXMLを書き出し(シート上の情報をもとにファイルを吐きだす),
- Ruby on RailsからXMLを読み込み(アップロードしてパース),
- Ruby on RailsからXMLを書き出す(ダウンロードさせる)。
という,双方向の流れを作る。
XMLを扱うために,それぞれライブラリとして
- VBA側 : MSXML
- ruby側 : REXML
を利用。
想定XML:
<hoge> <fuga id="1">a</fuga> <fuga id="2">b</fuga> </hoge>
(1)VBAでXML読み込み(MSXML)
ツール>参照設定
Microsoft XML v5.0
にチェック。
' 指定されたパスのXMLを読み込んでシートに反映 Sub load_xml( input_path ) Set xml = New MSXML2.DOMDocument ' 読み込み xml.Load input_path Set elem_hoge = xml.getElementsByTagName("hoge").Item(0) ' 子要素をリストアップ i = 1 For Each elem_fuga In elem_hoge.getElementsByTagName("fuga") Cells(i, 1).Value = elem_fuga.getAttribute("id") Cells(i, 2).Value = elem_fuga.Text i = i + 1 Next elem_fuga MsgBox "読み込みました。" End Sub
読み込み用のコードに出現するキーワード
- Load
- getElementsByTagName
- getAttribute
(2)VBAでXML書き込み(MSXML)
' 指定されたパスにXML書き出し Sub save_xml( output_path ) Set xml = New MSXML2.DOMDocument ' データ作成 xml.appendChild xml.createProcessingInstruction("xml", "version='1.0' encoding='SHIFT-JIS'") Set elem_hoge = xml.appendChild(xml.createElement("hoge")) ' 子要素を追加 For i = 1 To 2 Set elem_fuga = xml.createElement("fuga") elem_fuga.setAttribute "id", Cells(i, 1).Value elem_fuga.Text = Cells(i, 2).Value Next i ' 保存 xml.Save output_path MsgBox "書き出しました。" End Sub
書き出し用のコードに出現するキーワード
- createElement
- createProcessingInstruction
- appendChild
- setAttribute
- Save
(3)Ruby on RailsでXML読み込み(REXML)
アップロードしたXMLの内容を読み取ってDB登録するような状況を想定。
コントローラ側
# アップロードされたXMLを解析するアクション def upload_xml # アップロード時のnameを指定 xml_txt = params["xml_file"].read # 解析 モデル名.parse_xml( xml_txt ) end
モデル側
require "rexml/document" # XMLを読み込みます。 def self.parse_xml( xml_txt ) # パース xml = REXML::Document.new xml_txt # 子要素を解析 elem_hoge = xml.elements["hoge"] elem_hoge.each{|elem_fuga| fuga_id = elem_fuga.attributes["id"] fuga_text = elem_fuga.get_text.to_s # 解析データを使った処理(DB登録とか) # 〜 } nil end
キーワード:
- elements
- each
- attributes
- get_text
ビュー側では,formのenctypeを"multipart/form-data"にするのを忘れずに。
なお,注意点として,get_textは文字列ではなく「テキストノード」を返す。
したがって,get_text.length とかやってしまうとNoMethodErrorを起こすので用心の事。
(4)Ruby on RailsでXML書き出し(REXML)
DBの内容を読み取ってXML形式でダウンロードするような状況を想定。
コントローラ側
# XMLをダウンロードするアクション def download_xml xml_txt = モデル名.get_xml # ダウンロードさせる send_data( xml_txt, :type => "text/xml; charset=shift_jis; ", :filename => "boo.xml" ) # 画面に表示したい場合 #render( :text => xml_txt, :layout => false ) end
モデル側
require "rexml/document" require "nkf" # XMLを書き出します。 def self.get_xml # データ生成 xml = REXML::Document.new xml << REXML::XMLDecl.new( "1.0", "Shift-JIS" ) # 子要素を追加 elem_hoge = xml.add_element( "hoge" ) elem_fuga = elem_hoge.add_element( "fuga" ) elem_fuga.add_attributes({ "id" => 1 }) elem_fuga.add_text "a" # 文字列にダンプ xml_txt_utf8 = "" xml.write( xml_txt_utf8 ) # 出力先ストリームとして文字列変数を指定 # 文字コードを変換(VBAに読ませるために) xml_txt_sjis = NKF.nkf( "-U -s -Lw", xml_txt_utf8 ) return xml_txt_sjis end
キーワード:
- add_element
- add_attributes
- add_text
- write
注意点:
- xml.writeを呼び出す際に,文字コードに注意すること。XML内の冒頭の宣言で「UTF-8」としているのに,XMLの内容がEUCで書かれていたりすると,このメソッドを呼んだ時点で例外が発生してしまう。
補足
参考リンク
VBAでxmlの情報を読み込む(MSXML)
http://pugiemonn.blog6.fc2.com/blog-e...RubyでXML操作(REXML)
http://www.nslabs.jp/ruby-rexml.rhtml
関連エントリ:
Railsで,簡単にメッセージ管理する方法 (メッセージ定義書からメッセージ処理クラスを自動生成するVBAマクロ)
http://language-and-engineering.hatenablog.jp/entry/20090704/p1
Ruby on Railsのマイグレーションで,テストデータやサンプルデータをうまく管理する方法
http://language-and-engineering.hatenablog.jp/entry/20091211/p1
Ruby on Railsのバージョン間での違いのまとめ 一覧表(1系・2系・3系の差異と歴史)
http://language-and-engineering.hatenablog.jp/entry/20110913/p1