Ruby:コンピューティング業界を席巻するスクリプト言語
昨今のプログラミング業界で、REXMLの名前を耳にしたことのない人はまずいないでしょう。人気上昇中のWebアプリケーションフレームワークであるRuby on Railsのおかげで、Rubyはアプリケーションの開発およびテストを短時間で行うための言語として支持されています。インタープリタ型スクリプト言語であるRubyでは、手軽で簡単なオブジェクト指向プログラミングを行うことができ、さらに、クロージャ、ブロック、ミックスイン(Mixin)などの優れた機能を使用できます。また、移植性が非常に高く、Unix/Linux、Windows、MacOSすべてで動作します。Rubyについてもっと詳しく知りたい方は、W. Jason GilmoreのRubyに関する記事をお読みください。
REXML:XML処理を簡易化するRuby用プロセッサ
REXMLはJava用電子XMLライブラリに端を発するRuby XMLプロセッサです。使いやすいAPIを備えており、サイズが小さく高速で動作するだけでなく、ツリー解析とストリーム解析の両方の文書解析をサポートします。ストリーム解析はツリー解析よりも約1.5倍高速ですが、XPathなどの機能を利用できません。
REXMLを使用するには
REXMLを利用するには、まず、Rubyファイル内でREXMLをインクルードする必要があります。
require "rexml/document"
include REXML # so that we don’t have to prefix everything
# with REXML::...
これにより、REXMLライブラリとREXML名前空間がインクルードされ、メソッド呼び出しの前に"REXML"プレフィックスを付ける必要がなくなります。
では、REXMLを使用してシンプルなXML文書を作成し、プリントしてみましょう。「REXMLtest.rb」ファイルに次のRubyコードを入力し、保存します。
require "rexml/document"
include REXML # so that we don’t have to prefix everything
# with REXML::...
string = <<EOF
<xml>
<element attribute="attr">My first REXML document</element>
</xml>
EOF
doc = Document.new string
print doc
コマンドラインから次のように入力して「REXMLtest.rb」を実行し、その結果を確認します。
ここでは、シンプルなXML文書を含む文字列を作成し、その文字列を使用して新しいREXML文書オブジェクトを初期化し、最後にXML文書をプリントしました。
XML要素をツリー解析し、その要素にアクセスする
次は、XML文書を解析し、REXMLでXML文書内の要素にアクセスする方法を見てみます。まず、次のようなXML文書「guitars.xml」を作成します。
<guitars title="My Guitars">
<make name="Fender">
<model sn="123456789" year="2006" country="japan">
<name>62 Reissue Stratocaster</name>
<price>750.00</price>
<color>Fiesta Red</color>
</model>
<model sn="112233445" year="2006" country="mexico">
<name>60s Reverse Headstock Stratocaster</name>
<price>699.00</price>
<color>Olympic White</color>
</model>
</make>
<make name="Squier">
<model sn="445322344" year="2003" country="China">
<name>Standard Stratocaster</name>
<price>179.99</price>
<color>Cherry Sunburst</color>
</model>
</make>
</guitars>
この「guitars.xml」を、REXMLを使用して読み込み、プリントします。そのためには、次のような内容のRubyファイル「REXMLFileTest.rb」を作成します。
require "rexml/document"
include REXML # so that we don’t have to prefix everything
# with REXML::...
doc = Document.new File.new("guitars.xml")
print doc
「REXMLFileTest.rb」を実行すると、次のようなプリント結果が表示されます。
今度は、文書内の一部の情報をプリントしてみましょう。まず、この文書に記載されているギターの色をすべてプリントします。それには、文書中の個々のguitars/make/model/color要素にアクセスし、要素内のテキストをプリントします。
include REXML # so that we don’t have to prefix everything
# with REXML::...
doc = Document.new File.new("guitars.xml")
doc.elements.each("guitars/make/model/color")
{ |element| puts element.text }
Rubyスクリプトを再度実行すると、ギターの色がプリントされます。
次に、これらのギターの値段を合計します。各price要素をtotalに加算し、そのtotalをプリントします。
require "rexml/document"
include REXML # so that we don’t have to prefix everything with
# REXML::...
doc = Document.new File.new("guitars.xml")
# print doc
# doc.elements.each("guitars/make/model/color")
# { |element| puts element.text }
total = 0
doc.elements.each("guitars/make/model/price") { |element|
total += element.text.to_i
}
puts "Total is $" + total.to_s
このスクリプトを実行すると、次のように出力されます。
XPath式
REXMLはXPathもサポートします。XPathを使用すると、OSのファイルシステムのディレクトリに似た構文を使用して、XML文書の一部にアクセスできます。では、ギターリストの最初のmodelをプリントしてみましょう。そのためには、XML文書内の最初のmodel要素を探す必要があります。この処理をREXMLのXPath APIを使用して実行するには、次のコードを使用します。
require "rexml/document"
include REXML # so that we don’t have to prefix everything with
# REXML::...
doc = Document.new File.new("guitars.xml")
# print doc
firstmodel = XPath.first( doc, "//model" )
print firstmodel
XPath.firstは、コレクション内の最初の要素を返すメソッドです。このメソッドを使用して、doc文書内の最初の要素を取得できます。ここでは、XPath.firstに"//model"というXPath式を指定することで、ルート要素("//"で指定)から検索をスタートし、すべてのmodel要素を探すよう指示しています。このスクリプトを実行すると、次のように出力されます。
次は、すべてのギターの年式をプリントします。年式はmodel要素のyear属性として格納されています。この処理を行うには、XPath.eachメソッドに//model/attribute::yearというXPath式を渡します。
require "rexml/document"
include REXML # so that we don’t have to prefix everything with
# REXML::...
doc = Document.new File.new("guitars.xml")
XPath.each( doc, "//model/attribute::year")
{ |element| puts element }
このスクリプトを実行すると、次のように出力されます。
REXMLで文書を更新する
REXMLでXML文書要素にアクセスする方法を理解したところで、今度はREXML APIを使って文書を更新してみましょう。APIを使用して、新しいギターメーカーとそのメーカーのモデルを1つ追加します。「REXMLUpdateTest.rb」という名前の新しいファイルに、次のコードを入力してください。
require "rexml/document"
include REXML # so that we don’t have to prefix everything with
# REXML::...
doc = Document.new File.new("guitars.xml")
root = doc.root
make = Element.new "make"
make.attributes["name"] = "Gibson"
model = Element.new "model"
model.attributes["sn"] = "99999999"
model.attributes["year"] = "2007"
model.attributes["country"] = "USA"
model.add_element "name"
model.elements["name"].text = "SG"
model.add_element "price"
model.elements["price"].text = "1250.00"
model.add_element "color"
model.elements["color"].text = "Red"
make.add_element model
root.add_element make
print doc
このコードでは、まず文書のルート要素を取得し、その要素を変数rootに格納します。次に、make要素とmodel要素を作成します。属性と要素の両方をmodel要素内に作成していることに注目してください。そして最後に、modelをmakeの子要素として追加し、makeを文書ルートに追加しました。このスクリプトを実行すると、次のように表示されます。
ギターリストに新しいメーカーとそのメーカーのモデルが追加されました。
まとめ
この記事では、REXMLライブラリに注目し、このライブラリを使って、RubyアプリケーションやRailsアプリケーションでXMLを処理する方法を紹介しました。RubyやRailsでは大抵のことが簡単にできますが、REXMLでも同様に、セットアップとプログラミングを簡単かつ直感的に行うことができます。
REXMLを利用すると、XMLサポートを容易にアプリケーションに追加できます。操作の習得も簡単です。REXMLが提供する機能は他にも多数あるので、じっくり調べて、役に立つものがないかどうか確認してみてください。
参考資料