カテゴリ別 2003年 | 2004年 | 2005年 | 2006年 | 2007年 | 2008年
知り合いサイト: よんだもの / 暴想 / Linuxでやる夫 / 新宿Vipper / 僕だけが幸せになればいいのに。
XML を取り扱う必要が出たのですが、最近 Hpricot づいてますので、Hpricot で XML をパースすることにしました。
対象の XML が単なるデータ表現でしたので、オブジェクト化しやすいように、ノードを辿ってハッシュ・配列化するメソッドを書いてみました。とりあえず動いてますが、もう少しコードを整理したいところです。
require 'rubygems'
require 'hpricot'
def traverse(node, hash = {})
case node
when Hpricot::Elem
have_siblings = (node/"../#{node.name}").size > 1
if have_siblings
hash[node.name] ||= []
end
if node.children.size > 1
child_hash = {}
if have_siblings
hash[node.name] << child_hash
else
hash[node.name] = child_hash
end
node.each_child do |child|
traverse(child, child_hash)
end
else
if have_siblings
hash[node.name] << node.inner_html
else
hash[node.name] = node.inner_html
end
end
when Hpricot::Elements
node.each do |child|
traverse(child, hash)
end
end
hash
end
doc = Hpricot.XML(<<_XML_)
<Export>
<Product>
<SKU>403276</SKU>
<ItemName>Trivet</ItemName>
<CollectionNo>0</CollectionNo>
<Pages>0</Pages>
</Product>
<Product>
<SKU>104577</SKU>
<ItemName>Dish</ItemName>
<CollectionNo>1</CollectionNo>
<Pages>2</Pages>
</Product>
</Export>
_XML_
pp traverse(doc/:Export)
#=> {"Export"=>
{"Product"=>
[{"ItemName"=>"Trivet",
"Pages"=>"0",
"SKU"=>"403276",
"CollectionNo"=>"0"},
{"ItemName"=>"Dish",
"Pages"=>"2",
"SKU"=>"104577",
"CollectionNo"=>"1"}]}}
XML のサンプルはerr.the_blog.find_by_title('Parse XML with Hpricot')から借りました。
今、Miyakoのマップスクロールとか、Miyako::Screen.updateメソッドとかが遅いと感じるときがあるので、そこをC拡張でなんとかできないかと試しています。
ただ、「既存のモジュール(require済みと仮定)にモジュールメソッドを追加する」方法が、ドキュメントを読んだだけでは分からない。
Ruby拡張ライブラリのいいソース無いかなぁ?
README.EXT だけだと難しいかもしれないですね。
Pure Ruby で定義された Hoge クラスに対して、C 言語の拡張で hoge インスタンスメソッドを追加する方法というかソース例を説明します。
ファイルを三つ用意してください。extconf.rb、C 拡張ライブラリのソース、それを使う Ruby プログラムです。
全体では以下のような流れのプログラムです。
Makefile 生成用。これを実行すると exthoge.c をコンパイルして exthoge.so を作成する Makefile が作成されます。
require 'mkmf'
create_makefile('exthoge')
拡張ライブラリのソース。Hoge#hoge を定義します。Init_**** は require されたときに実行されるスタートアップルーチンです。**** は create_makefile した拡張ライブラリ名と一致させます。この例では、create_makefile('exthoge') したので Init_exthoge です。
Ruby ではクラスは定数に結び付けられてますので、rb_const_get で取得できます。(rb_cObject から取得していいのかはちょっと不明です。)
#include
static VALUE rb_hoge_hoge(VALUE obj)
{
return rb_str_new2("hoge");
}
void Init_exthoge()
{
VALUE cHoge;
cHoge = rb_const_get(rb_cObject, rb_intern("Hoge"));
rb_define_method(cHoge, "hoge", rb_hoge_hoge, 0);
}
Hoge クラスを定義し、また exthoge 拡張ライブラリを読み込んで Hoge#hoge を呼び出します。
class Hoge
end
require 'exthoge'
hoge = Hoge.new
p hoge.hoge #=> "hoge"
extronf.rb を実行して Makefile を作成、あとは make すれば拡張ライブラリができます。Linux 環境前提ですが。
$ ruby extconf.rb creating Makefile $ make i686-pc-linux-gnu-gcc -shared -o exthoge.so exthoge.o -L'.' -L'/usr/lib' -Wl,-R'/usr/lib' -L. -rdynamic -Wl,-export-dynamic -Wl,-R -Wl,/usr/lib -L. -L/usr/lib -lruby18 -lpthread -ldl -lcrypt -lm -lc $ ls -l exthoge.so -rwxr-xr-x 1 date users 6529 2007-08-14 23:46 exthoge.so
インスタンス変数は rb_iv_get で取得できます。後は ruby.h を眺めながら色々試すしかないですね。最悪 Ruby の eval 相当の rb_eval_string を使えば大体何でもできます。
最近のコメント:
RSS
![]()
This work is licensed under a
Creative Commons License
(note: text only. w/o web design, citations, (re)distributed softwares).
失礼をばいたしました・・・。<br>ご教授ありがとうございます。<br>試してみたのですが、かなり凄い量の関数呼び出しになりますね・・・(^^;
rb_const_get(rb_cObject)してもいいのですが、<br>class/moduleに限定するならrb_path2class()という関数もあります。
>サイロスさん<br>参考になれば幸いです。<br><br>>ながださん<br>rb_path2class は知りませんでした。便利ですね。