K.Sasada's Home Page

REXML であそぶ

Thu, 26 Sep 2002 17:56:41 +0900、初稿。

って?

REXML 。もしくは ヒント: 軽量XMLライブラリー

Ruby で XML を使うためのなにからしい。

DOM っぽいのとか、SOX っぽいのとか、XPath とかできるらしい。便利だ。

今まで、JavaでXercs 使ったり C++ で Xercs 使ったり(Xercs しかつかってねーのかよ)、してみたんだけれど、面倒くさすぎて使ってきませんでした。というわけで、Ruby で楽しくできるならいいなぁーと思い、やってみました。

準備

本家から、REMXL とか、APIリファレンスとか、落としてきましょう。また、日本語版REXML APIドキュメント を須藤さんがメンテナンスされております。感謝。

また、Uconv モジュールが必要になります。REXMLは内部では全て UTF-8 Encode で扱ってるらしく、その他の文字コードで書いてある XML 文書を読みこむ場合、また、それを出力する場合に必要になります。

  1. ブツを落とす(REXML,docs,etc)。
  2. インストールする。(ruby bin/install.rb で簡単)
  3. Uconv を落とす。
  4. Uconv をインストールする。(ruby extconf.rb ; nmake ; make install)

で、準備はおわり。

Uconv のインストール、make じゃなくて、nmake を使うってことにはまりました。あはは。

とりあえず使ってみる

とりあえず使ってみる。

REXML Tutorial を見ながら、ちょいちょい書いてみる。

どうやら、File のインスタンスを REXML::Document.new に渡せば、DOMっぽいものを勝手に作ってくれるらしい。楽だ。

というわけで、やってみる。

適当にちょいちょい書いた Ruby script は次の通り。

#/usr/ruby -Ks

require 'rexml/document'

file = File.new "test.xml"
doc = REXML::Document.new file

$rank = 0

def sp
  "  " * $rank
end
def run elem
  print "================================\n"
  print sp + "name : #{elem.name}\n"
  attrs = elem.attributes
  attrs.each{|a,e|
    print sp + "attr : #{a} = #{e}\n"
  }
  text = Uconv.u8tosjis elem.text if elem.text != nil
  print sp + "text : \n--\n#{text}\n--\n"
  if elem.has_elements? then
    elem.each_element{|e|
      $rank += 1
      run e
      $rank -= 1
    }
  end
end

# p doc.has_elements?
run doc.root

サンプルのための test.xml は次のとおり。

<test>
  root text
  <hoe>
	hoehoe0
  </hoe>
  <hoe h="1">
	hoehoe1
  </hoe>
</test>

結果。

================================
name : test
text : 
--

  root text
  
--
================================
  name : hoe
  text : 
--

	hoehoe0
  
--
================================
  name : hoe
  attr : h = 1
  text : 
--

	hoehoe1
  
--

うーん、おき楽。

一応、ポイントを。

次の実験

上のスクリプトに、このサイトの xhtml を食わせてみる。

でかいので、ここには結果を載せないが、きちんとパースされているのがわかった。

実は、この実験で、invalid なXML な部分があることを発見 ^^;(タグの不整合)。いやー、やれやれ。(DTD定義とかまで考えると、きっともっとまずいのはあるんだろうな)。

element を加えてみる

DOM Tree (で、いいのか?)に、element を足してみる。

#/usr/ruby -Ks

require 'uconv'
require 'rexml/document'

file = File.new "test.xml"
doc = REXML::Document.new file

# p doc.has_elements?
print doc.root
print "\n------------------------------------------------------\n"

# add
def add_elem elem
  if elem.name == "hoe"
    ne = REXML::Element.new "hue"
    ne.text = "huehue"
    elem.add_element ne
  end
  if elem.has_elements? then
    elem.each_element{|e|
      add_elem e
    }
  end
end

add_elem doc.root

print doc.root

結果。

<test>
  root text
  <hoe>
	hoehoe0
  </hoe>
  <hoe h='1'>
	hoehoe1
  </hoe>
</test>
------------------------------------------------------
<test>
  root text
  <hoe>
	hoehoe0
  <hue>huehue</hue></hoe>
  <hoe h='1'>
	hoehoe1
  <hue>huehue</hue></hoe>
</test>

うむ、きちんと足されている。しかし、インデントがされておらず、なんとも気持ちが悪いのは、俺だけだろうか。

ちなみに、ソースでやっているけれど、elem.to_s は、綺麗にxmlを吐いてくれるらしい。楽だ。

次は?

一番やりたかったことは、日記のページに自動で挿入させたり、ってことだったのだけれど、うーん、それは今度かな。

まとめ

これで私も XML であそべそうです。結構ゆっくりだけれど、個人ユースにはこれくらいでちょうどいいか。

実は、text 処理を、その都度書いていったほうが速いのかなぁと、思わないでもなかったり。

Sasada Koichi / sasada@namikilab.tuat.ac.jp
$Date: 2002/09/27 08:37:11 $